46 const std::string& url) = 0;
56 std::chrono::seconds timeout) = 0;
110 : config_(std::move(config)),
112 metadata_endpoint_(metadata_endpoint),
113 token_endpoint_(token_endpoint),
114 pkce_generator_(pkce_generator),
115 registration_endpoint_(registration_endpoint) {}
128 auto discovery_result = discovery.discover(config_.
resource_url);
129 if (!discovery_result.has_value()) {
130 return core::unexpected(discovery_result.error());
133 metadata_ = discovery_result->authorization_server;
134 protected_resource_ = discovery_result->protected_resource;
136 if (!metadata_.has_value()) {
138 OAuthErrorCode::kMetadataDiscoveryFailed,
139 "no authorization server metadata discovered for resource",
145 manager_.set_authorization_server_metadata(*metadata_);
146 manager_.set_token_endpoint(std::shared_ptr<OAuthTokenEndpoint>(
148 if (registration_endpoint_ !=
nullptr) {
149 manager_.set_client_registration_endpoint(
150 std::shared_ptr<OAuthClientRegistrationEndpoint>(
159 client_options.scopes = config_.
scopes;
162 manager_.configure_client_for_authorization(client_options);
175 auto pkce = pkce_generator_.create_s256();
176 if (!pkce.has_value()) {
177 return core::unexpected(pkce.error());
180 auto state = generate_state();
184 session_request.client.client_name = config_.
client_name;
185 session_request.client.redirect_uri = manager_.client_config().redirect_uri;
186 session_request.client.scopes = config_.
scopes;
187 session_request.pkce = *pkce;
188 session_request.state = state;
189 auto session_result = manager_.start_session(std::move(session_request));
190 if (!session_result.has_value()) {
191 return core::unexpected(session_result.error());
195 session_result->authorization_url());
196 if (!present_result.has_value()) {
197 return core::unexpected(present_result.error());
201 auto callback_result =
203 if (!callback_result.has_value()) {
204 return core::unexpected(callback_result.error());
207 auto& [code, callback_state] = *callback_result;
210 auto tokens = manager_.exchange_authorization_code(code, callback_state);
211 if (!tokens.has_value()) {
212 return core::unexpected(tokens.error());
238 return manager_.refresh_after_unauthorized_response(response);
243 return manager_.lifecycle_state();
248 return manager_.client_config();
252 const std::optional<AuthorizationServerMetadata>&
metadata()
const {
259 return protected_resource_;
263 static std::string generate_state() {
266 static constexpr char kHex[] =
"0123456789abcdef";
272 auto seed =
static_cast<std::uint64_t
>(
273 SystemClock::now().time_since_epoch().count());
274 for (
int i = 0; i < 32; ++i) {
275 seed = seed * 6364136223846793005ULL + 1442695040888963407ULL;
276 result.push_back(kHex[(seed >> 16) & 0xF]);
281 OAuthClientOrchestratorConfig config_;
282 OAuthClientCallback& callback_;
283 OAuthMetadataEndpoint& metadata_endpoint_;
284 OAuthTokenEndpoint& token_endpoint_;
285 PkceGenerator& pkce_generator_;
286 OAuthClientRegistrationEndpoint* registration_endpoint_;
288 AuthorizationManager manager_;
289 std::optional<AuthorizationServerMetadata> metadata_;
290 std::optional<ProtectedResourceMetadata> protected_resource_;
293class OAuthClientFlowBuilder;
333 const std::optional<AuthorizationServerMetadata>&
metadata()
const {
348 std::shared_ptr<OAuthClientCallback> callback,
349 std::shared_ptr<OAuthMetadataEndpoint> metadata_endpoint,
350 std::shared_ptr<OAuthTokenEndpoint> token_endpoint,
351 std::shared_ptr<PkceGenerator> pkce_generator,
352 std::shared_ptr<OAuthClientRegistrationEndpoint> registration_endpoint)
353 : config_(std::move(config)),
354 callback_(std::move(callback)),
355 metadata_endpoint_(std::move(metadata_endpoint)),
356 token_endpoint_(std::move(token_endpoint)),
357 pkce_generator_(std::move(pkce_generator)),
358 registration_endpoint_(std::move(registration_endpoint)),
360 config_, *callback_, *metadata_endpoint_, *token_endpoint_,
362 registration_endpoint_ ? registration_endpoint_.get() : nullptr) {}
364 OAuthClientOrchestratorConfig config_;
365 std::shared_ptr<OAuthClientCallback> callback_;
366 std::shared_ptr<OAuthMetadataEndpoint> metadata_endpoint_;
367 std::shared_ptr<OAuthTokenEndpoint> token_endpoint_;
368 std::shared_ptr<PkceGenerator> pkce_generator_;
369 std::shared_ptr<OAuthClientRegistrationEndpoint> registration_endpoint_;
370 OAuthClientOrchestrator orchestrator_;
396 config_.
scopes = std::move(value);
426 callback_ = non_owning(value);
432 callback_ = std::move(value);
438 metadata_endpoint_ = non_owning(value);
444 std::shared_ptr<OAuthMetadataEndpoint> value) {
445 metadata_endpoint_ = std::move(value);
451 token_endpoint_ = non_owning(value);
457 std::shared_ptr<OAuthTokenEndpoint> value) {
458 token_endpoint_ = std::move(value);
465 std::make_shared<HttpOAuthMetadataEndpoint>(std::move(get));
466 token_endpoint_ = std::make_shared<HttpOAuthTokenEndpoint>(std::move(post));
472 pkce_generator_ = non_owning(value);
478 pkce_generator_ = std::move(value);
485 registration_endpoint_ = non_owning(value);
491 std::shared_ptr<OAuthClientRegistrationEndpoint> value) {
492 registration_endpoint_ = std::move(value);
498 return std::move(*this).build();
503 auto validation = validate();
504 if (!validation.has_value()) {
505 return core::unexpected(validation.error());
509 std::move(config_), std::move(callback_), std::move(metadata_endpoint_),
510 std::move(token_endpoint_), std::move(pkce_generator_),
511 std::move(registration_endpoint_)));
515 template <
typename T>
516 static std::shared_ptr<T> non_owning(T& value) {
517 return std::shared_ptr<T>(&value, [](T*) {});
520 core::Result<core::Unit> validate()
const {
522 return core::unexpected(make_oauth_error(OAuthErrorCode::kInvalidRequest,
523 "resource_url is required"));
526 return core::unexpected(
528 "OAuth client callback is required"));
530 if (!metadata_endpoint_) {
531 return core::unexpected(
533 "OAuth metadata endpoint is required"));
535 if (!token_endpoint_) {
537 OAuthErrorCode::kInvalidRequest,
"OAuth token endpoint is required"));
539 if (!pkce_generator_) {
541 "PKCE generator is required"));
546 OAuthClientOrchestratorConfig config_;
547 std::shared_ptr<OAuthClientCallback> callback_;
548 std::shared_ptr<OAuthMetadataEndpoint> metadata_endpoint_;
549 std::shared_ptr<OAuthTokenEndpoint> token_endpoint_;
550 std::shared_ptr<PkceGenerator> pkce_generator_;
551 std::shared_ptr<OAuthClientRegistrationEndpoint> registration_endpoint_;
Shared lightweight value types for cxxmcp auth contracts.
Callback interface for the OAuth client orchestrator.
Definition client_orchestrator.hpp:38
virtual core::Result< std::pair< std::string, std::string > > wait_for_callback(std::chrono::seconds timeout)=0
Wait for the authorization code callback.
virtual core::Result< core::Unit > present_authorization_url(const std::string &url)=0
Present the authorization URL to the user (e.g.
Fluent builder for the common OAuth browser authorization flow.
Definition client_orchestrator.hpp:374
OAuthClientFlowBuilder & registration_endpoint(std::shared_ptr< OAuthClientRegistrationEndpoint > value)
Set an owning dynamic client registration endpoint.
Definition client_orchestrator.hpp:490
core::Result< std::unique_ptr< OAuthClientFlow > > build() &
Build the owning flow wrapper.
Definition client_orchestrator.hpp:497
OAuthClientFlowBuilder & redirect_uri(std::string value)
Set the redirect URI used by the authorization code flow.
Definition client_orchestrator.hpp:401
OAuthClientFlowBuilder & resource_url(std::string value)
Set the MCP protected resource URL.
Definition client_orchestrator.hpp:383
OAuthClientFlowBuilder & metadata_endpoint(OAuthMetadataEndpoint &value)
Set a non-owning metadata endpoint reference.
Definition client_orchestrator.hpp:437
OAuthClientFlowBuilder & registration_endpoint(OAuthClientRegistrationEndpoint &value)
Set a non-owning dynamic client registration endpoint reference.
Definition client_orchestrator.hpp:483
OAuthClientFlowBuilder & callback(std::shared_ptr< OAuthClientCallback > value)
Set an owning application callback.
Definition client_orchestrator.hpp:431
OAuthClientFlowBuilder & pkce_generator(PkceGenerator &value)
Set a non-owning PKCE generator reference.
Definition client_orchestrator.hpp:471
OAuthClientFlowBuilder & client_name(std::string value)
Set the display name used during dynamic client registration.
Definition client_orchestrator.hpp:389
OAuthClientFlowBuilder & scopes(ScopeList value)
Set requested OAuth scopes.
Definition client_orchestrator.hpp:395
OAuthClientFlowBuilder & http_endpoints(OAuthHttpGet get, OAuthHttpPost post)
Set the default HTTP metadata and token endpoints.
Definition client_orchestrator.hpp:463
core::Result< std::unique_ptr< OAuthClientFlow > > build() &&
Build the owning flow wrapper.
Definition client_orchestrator.hpp:502
OAuthClientFlowBuilder & metadata_endpoint(std::shared_ptr< OAuthMetadataEndpoint > value)
Set an owning metadata endpoint.
Definition client_orchestrator.hpp:443
OAuthClientFlowBuilder & callback_timeout(std::chrono::seconds value)
Set the maximum wait time for the authorization callback.
Definition client_orchestrator.hpp:407
OAuthClientFlowBuilder & pkce_generator(std::shared_ptr< PkceGenerator > value)
Set an owning PKCE generator.
Definition client_orchestrator.hpp:477
OAuthClientFlowBuilder & refresh_skew(std::chrono::seconds value)
Set the proactive token refresh skew.
Definition client_orchestrator.hpp:413
OAuthClientFlowBuilder & token_endpoint(std::shared_ptr< OAuthTokenEndpoint > value)
Set an owning token endpoint.
Definition client_orchestrator.hpp:456
OAuthClientFlowBuilder & client_id(std::string value)
Use a preconfigured client_id and skip dynamic registration.
Definition client_orchestrator.hpp:419
OAuthClientFlowBuilder & token_endpoint(OAuthTokenEndpoint &value)
Set a non-owning token endpoint reference.
Definition client_orchestrator.hpp:450
OAuthClientFlowBuilder & callback(OAuthClientCallback &value)
Set a non-owning application callback reference.
Definition client_orchestrator.hpp:425
Built common browser + PKCE OAuth client flow.
Definition client_orchestrator.hpp:301
const std::optional< ProtectedResourceMetadata > & protected_resource_metadata() const
Get the discovered protected resource metadata.
Definition client_orchestrator.hpp:338
core::Result< TokenSet > authorize()
Execute discovery, client setup, authorization, and token exchange.
Definition client_orchestrator.hpp:309
const std::optional< AuthorizationServerMetadata > & metadata() const
Get the discovered authorization server metadata.
Definition client_orchestrator.hpp:333
core::Result< std::string > get_access_token()
Return a currently valid access token, refreshing when needed.
Definition client_orchestrator.hpp:312
core::Result< OAuthRefreshRetryResult > handle_auth_response(const HttpResponseMetadata &response)
Handle an unauthorized HTTP response and decide whether to retry.
Definition client_orchestrator.hpp:317
const OAuthClientConfig & client_config() const
Get the current client configuration.
Definition client_orchestrator.hpp:328
OAuthLifecycleState lifecycle_state() const
Get the current lifecycle state.
Definition client_orchestrator.hpp:323
High-level OAuth 2.1 client orchestrator.
Definition client_orchestrator.hpp:93
const std::optional< ProtectedResourceMetadata > & protected_resource_metadata() const
Get the discovered protected resource metadata.
Definition client_orchestrator.hpp:257
core::Result< TokenSet > authorize()
Execute the full OAuth authorization flow.
Definition client_orchestrator.hpp:125
OAuthLifecycleState lifecycle_state() const
Get the current lifecycle state.
Definition client_orchestrator.hpp:242
OAuthClientOrchestrator(OAuthClientOrchestratorConfig config, OAuthClientCallback &callback, OAuthMetadataEndpoint &metadata_endpoint, OAuthTokenEndpoint &token_endpoint, PkceGenerator &pkce_generator, OAuthClientRegistrationEndpoint *registration_endpoint=nullptr)
Construct an orchestrator with all required dependencies.
Definition client_orchestrator.hpp:105
core::Result< std::string > get_access_token()
Get a valid access token, refreshing if necessary.
Definition client_orchestrator.hpp:224
core::Result< OAuthRefreshRetryResult > handle_auth_response(const HttpResponseMetadata &response)
Handle a 401/403 response and attempt recovery.
Definition client_orchestrator.hpp:236
const OAuthClientConfig & client_config() const
Get the current client configuration.
Definition client_orchestrator.hpp:247
const std::optional< AuthorizationServerMetadata > & metadata() const
Get the discovered authorization server metadata.
Definition client_orchestrator.hpp:252
Dynamic client registration network boundary.
Definition registration.hpp:69
Token exchange and refresh network boundary.
Definition lifecycle.hpp:293
Public wrapper around the SDK's private PKCE implementation.
Definition pkce.hpp:30
OAuthClientFlowBuilder oauth_client_flow()
Start building the common OAuth browser authorization flow.
Definition client_orchestrator.hpp:555
Default OAuth token endpoint form encoder and JSON response parser.
std::function< core::Result< OAuthHttpResponse >(const OAuthHttpRequest &)> OAuthHttpPost
Application or SDK transport adapter used for token POST calls.
Definition http_token_endpoint.hpp:31
OAuth authorization lifecycle contracts and lightweight state logic.
OAuthLifecycleState
Runtime state for the interactive OAuth lifecycle.
Definition lifecycle.hpp:306
core::Error make_oauth_error(OAuthErrorCode code, std::string message, std::string detail={})
Build an auth-category lifecycle error.
Definition lifecycle.hpp:50
PKCE contracts for OAuth authorization-code flows.
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
Full client-id selection plus authorization URL request.
Definition lifecycle.hpp:861
Options used when selecting a client_id before authorization.
Definition registration.hpp:98
Public OAuth client configuration used by lifecycle helpers.
Definition types.hpp:41
Configuration for the OAuth client orchestrator.
Definition client_orchestrator.hpp:60
ScopeList scopes
Scopes to request. Empty = let the server decide.
Definition client_orchestrator.hpp:66
std::chrono::seconds refresh_skew
How long before token expiry to proactively refresh.
Definition client_orchestrator.hpp:74
std::string redirect_uri
Redirect URI for the authorization code flow.
Definition client_orchestrator.hpp:70
std::string client_name
Client name for dynamic client registration.
Definition client_orchestrator.hpp:64
std::chrono::seconds callback_timeout
Maximum time to wait for the authorization code callback.
Definition client_orchestrator.hpp:72
std::optional< std::string > client_id
Pre-configured client_id. When set, DCR is skipped.
Definition client_orchestrator.hpp:76
std::string resource_url
The MCP resource URL (e.g. "https://example.com/mcp").
Definition client_orchestrator.hpp:62
OAuth token models and storage contracts.
WWW-Authenticate challenge models and parser boundary.