chore: refactor OAuth client authorization api (#1009)

* refactor!: refactor OAuth client authorization api

`OAuthState::start_authorization` now accepts a declarative `AuthorizationRequest`
describing the client's available identity material and selects the highest-priority
mechanism the server supports: pre-registered client information → Client ID
Metadata Documents (SEP-991) → Dynamic Client Registration.

This replaces the three mechanism-specific entry points (`start_authorization`,
`start_authorization_with_metadata_url`, `start_authorization_with_preregistered_client`),
where callers previously had to know which mechanism to pick. `AuthorizationSession::new`
is consolidated the same way, and the failure-recovery pattern from #994 (returning the
manager alongside the error so `OAuthState` recovers to `Unauthorized` on transient failures)
is now applied across all registration paths. Includes new `RecordingOAuthHttpClient`-based
tests covering the priority matrix and recovery semantics, plus updated docs, examples, and
conformance client.

* fix: dcr registration uses requested application type

* fix: error for invalid combination
This commit is contained in:
Jack Amadeo 2026-07-23 14:13:11 -04:00 • committed by GitHub
commit e903341136
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -4,7 +4,7 @@ use rmcp::{
service::RequestContext,
transport::{
AuthClient, AuthorizationManager, StreamableHttpClientTransport,
auth::{AuthorizationCallback, InMemoryCredentialStore, OAuthState},
auth::{AuthorizationCallback, AuthorizationRequest, InMemoryCredentialStore, OAuthState},
streamable_http_client::StreamableHttpClientTransportConfig,
},
};
@ -206,11 +206,10 @@ async fn perform_oauth_flow(
// Discover + register + get auth URL
oauth
.start_authorization_with_metadata_url(
&[],
REDIRECT_URI,
Some("conformance-client"),
Some(CIMD_CLIENT_METADATA_URL),
.start_authorization(
AuthorizationRequest::new(REDIRECT_URI)
.with_client_name("conformance-client")
.with_client_metadata_url(CIMD_CLIENT_METADATA_URL),
)
.await?;
@ -255,10 +254,12 @@ async fn perform_oauth_flow_preregistered(
) -> anyhow::Result<AuthClient<reqwest::Client>> {
let mut oauth = OAuthState::new(server_url, None).await?;
let config = rmcp::transport::auth::OAuthClientConfig::new(client_id, REDIRECT_URI)
.with_client_secret(client_secret);
oauth
.start_authorization_with_preregistered_client(config)
.start_authorization(
AuthorizationRequest::new(REDIRECT_URI)
.with_preregistered_client(client_id)
.with_client_secret(client_secret),
)
.await?;
let auth_url = oauth.get_authorization_url().await?;
@ -323,11 +324,11 @@ async fn run_auth_scope_step_up_client(
) -> anyhow::Result<()> {
let mut oauth = OAuthState::new(server_url, None).await?;
oauth
.start_authorization_with_metadata_url(
SCOPE_STEP_UP_INITIAL_SCOPES,
REDIRECT_URI,
Some("conformance-client"),
Some(CIMD_CLIENT_METADATA_URL),
.start_authorization(
AuthorizationRequest::new(REDIRECT_URI)
.with_scopes(SCOPE_STEP_UP_INITIAL_SCOPES.iter().copied())
.with_client_name("conformance-client")
.with_client_metadata_url(CIMD_CLIENT_METADATA_URL),
)
.await?;
@ -375,11 +376,11 @@ async fn run_auth_scope_step_up_client(
let mut oauth2 = OAuthState::new(server_url, None).await?;
oauth2
.start_authorization_with_metadata_url(
SCOPE_STEP_UP_ESCALATED_SCOPES,
REDIRECT_URI,
Some("conformance-client"),
Some(CIMD_CLIENT_METADATA_URL),
.start_authorization(
AuthorizationRequest::new(REDIRECT_URI)
.with_scopes(SCOPE_STEP_UP_ESCALATED_SCOPES.iter().copied())
.with_client_name("conformance-client")
.with_client_metadata_url(CIMD_CLIENT_METADATA_URL),
)
.await?;
let auth_url2 = oauth2.get_authorization_url().await?;
@ -427,11 +428,10 @@ async fn run_auth_scope_retry_limit_client(
loop {
let mut oauth = OAuthState::new(server_url, None).await?;
oauth
.start_authorization_with_metadata_url(
&[],
REDIRECT_URI,
Some("conformance-client"),
Some(CIMD_CLIENT_METADATA_URL),
.start_authorization(
AuthorizationRequest::new(REDIRECT_URI)
.with_client_name("conformance-client")
.with_client_metadata_url(CIMD_CLIENT_METADATA_URL),
)
.await?;
let auth_url = oauth.get_authorization_url().await?;