21 StringList redirect_uris;
22 StringList grant_types;
23 StringList response_types;
25 std::optional<std::string> client_name;
26 std::optional<std::string> client_uri;
27 std::optional<std::string> logo_uri;
28 std::optional<std::string> contacts;
29 std::optional<std::string> token_endpoint_auth_method;
35 std::string client_id;
36 std::optional<std::string> client_secret;
37 std::optional<std::string> registration_access_token;
38 std::optional<std::string> registration_client_uri;
39 std::optional<std::string> client_id_issued_at;
40 std::optional<std::string> client_secret_expires_at;
47 std::string client_id;
54 std::string registration_endpoint;
61 std::string client_id_metadata_url;
91 std::string client_name =
"MCP Client";
92 std::string redirect_uri;
99 std::optional<std::string> client_id_metadata_url;
100 std::string client_name =
"MCP Client";
101 std::string redirect_uri;
104 MetadataMap metadata;
110 if (options.redirect_uri.empty()) {
111 return mcp::core::unexpected(
113 "redirect_uri is required for dynamic client registration",
115 std::string(AuthErrorCategory)});
119 request.redirect_uris = {options.redirect_uri};
120 request.grant_types = {
"authorization_code",
"refresh_token"};
121 request.response_types = {
"code"};
122 request.scope = options.scopes;
123 request.client_name =
124 options.client_name.empty() ?
"MCP Client" : options.client_name;
125 request.token_endpoint_auth_method =
"none";
126 request.metadata = options.metadata;
135 config.client_id = response.client_id;
136 if (response.client_secret.has_value() && !response.client_secret->empty()) {
137 config.client_secret = response.client_secret;
139 config.redirect_uri = std::move(redirect_uri);
140 config.scopes = std::move(scopes);
141 config.metadata = response.metadata;
150 config.client_id = document.client_id;
151 config.redirect_uri = std::move(redirect_uri);
152 config.scopes = std::move(scopes);
153 config.metadata = document.metadata;
159inline bool metadata_flag_enabled(
const MetadataMap& metadata,
160 std::string_view key) {
161 const auto iter = metadata.find(std::string(key));
162 if (iter == metadata.end()) {
165 return iter->second ==
"true" || iter->second ==
"1" || iter->second ==
"yes";
168inline bool segment_is_dot_reference(std::string_view segment) {
169 std::string normalized;
170 normalized.reserve(segment.size());
171 for (std::size_t index = 0; index < segment.size(); ++index) {
172 if (segment[index] ==
'%' && index + 2 < segment.size() &&
173 segment[index + 1] ==
'2' &&
174 (segment[index + 2] ==
'e' || segment[index + 2] ==
'E')) {
175 normalized.push_back(
'.');
179 normalized.push_back(segment[index]);
181 return normalized ==
"." || normalized ==
"..";
184inline bool url_contains_dot_segment(std::string_view path) {
186 while (pos <= path.size()) {
187 const auto next = path.find(
'/', pos);
188 const auto end = next == std::string_view::npos ? path.size() : next;
189 const auto segment = path.substr(pos, end - pos);
190 if (segment_is_dot_reference(segment)) {
193 if (next == std::string_view::npos) {
206 return detail::metadata_flag_enabled(metadata.metadata,
207 "client_id_metadata_document_supported");
212 constexpr std::string_view kHttps =
"https://";
213 if (url.substr(0, kHttps.size()) != kHttps) {
216 const auto authority_start = kHttps.size();
217 const auto path_start = url.find(
'/', authority_start);
218 if (path_start == std::string_view::npos || path_start + 1 >= url.size()) {
221 const auto authority =
222 url.substr(authority_start, path_start - authority_start);
223 if (authority.empty() || authority.find(
'@') != std::string_view::npos) {
226 const auto path = url.substr(path_start);
227 if (path.find(
'#') != std::string_view::npos ||
228 detail::url_contains_dot_segment(path)) {
Shared lightweight value types for cxxmcp auth contracts.
Dynamic client registration network boundary.
Definition registration.hpp:69
core::Result< ClientRegistrationRequest > build_client_registration_request(const ClientRegistrationOptions &options)
Build the default MCP OAuth DCR request for a public client.
Definition registration.hpp:109
bool supports_client_id_metadata_document(const AuthorizationServerMetadata &metadata)
Whether authorization metadata advertises URL-based client_id docs.
Definition registration.hpp:204
bool is_valid_client_id_metadata_url(std::string_view url)
Validate an SEP-991-style HTTPS URL client_id.
Definition registration.hpp:211
OAuthClientConfig oauth_client_config_from_registration_response(const ClientRegistrationResponse &response, std::string redirect_uri, ScopeList scopes)
Convert a successful DCR response into the SDK OAuth client config.
Definition registration.hpp:131
OAuthClientConfig oauth_client_config_from_metadata_document(const ClientIdMetadataDocument &document, std::string redirect_uri, ScopeList scopes)
Convert a Client ID Metadata Document into the SDK OAuth config.
Definition registration.hpp:146
Shared result and error primitives used by the public cxxmcp SDK.
tl::expected< T, Error > Result
Alias for the SDK result type.
Definition result.hpp:64
Options used when selecting a client_id before authorization.
Definition registration.hpp:98
Request sent through an application-provided DCR transport.
Definition registration.hpp:53
Options used to build a dynamic client registration request.
Definition registration.hpp:90
RFC 7591 dynamic client registration request.
Definition registration.hpp:20
Dynamic client registration response.
Definition registration.hpp:34
Public OAuth client configuration used by lifecycle helpers.
Definition types.hpp:41
Structured error returned by fallible SDK operations.
Definition result.hpp:35