Skip to content

Commit e903341

Browse files
authored
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
1 parent 5554a41 commit e903341

5 files changed

Lines changed: 625 additions & 219 deletions

File tree

conformance/src/bin/client.rs

Lines changed: 24 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use rmcp::{
44
service::RequestContext,
55
transport::{
66
AuthClient, AuthorizationManager, StreamableHttpClientTransport,
7-
auth::{AuthorizationCallback, InMemoryCredentialStore, OAuthState},
7+
auth::{AuthorizationCallback, AuthorizationRequest, InMemoryCredentialStore, OAuthState},
88
streamable_http_client::StreamableHttpClientTransportConfig,
99
},
1010
};
@@ -206,11 +206,10 @@ async fn perform_oauth_flow(
206206

207207
// Discover + register + get auth URL
208208
oauth
209-
.start_authorization_with_metadata_url(
210-
&[],
211-
REDIRECT_URI,
212-
Some("conformance-client"),
213-
Some(CIMD_CLIENT_METADATA_URL),
209+
.start_authorization(
210+
AuthorizationRequest::new(REDIRECT_URI)
211+
.with_client_name("conformance-client")
212+
.with_client_metadata_url(CIMD_CLIENT_METADATA_URL),
214213
)
215214
.await?;
216215

@@ -255,10 +254,12 @@ async fn perform_oauth_flow_preregistered(
255254
) -> anyhow::Result<AuthClient<reqwest::Client>> {
256255
let mut oauth = OAuthState::new(server_url, None).await?;
257256

258-
let config = rmcp::transport::auth::OAuthClientConfig::new(client_id, REDIRECT_URI)
259-
.with_client_secret(client_secret);
260257
oauth
261-
.start_authorization_with_preregistered_client(config)
258+
.start_authorization(
259+
AuthorizationRequest::new(REDIRECT_URI)
260+
.with_preregistered_client(client_id)
261+
.with_client_secret(client_secret),
262+
)
262263
.await?;
263264

264265
let auth_url = oauth.get_authorization_url().await?;
@@ -323,11 +324,11 @@ async fn run_auth_scope_step_up_client(
323324
) -> anyhow::Result<()> {
324325
let mut oauth = OAuthState::new(server_url, None).await?;
325326
oauth
326-
.start_authorization_with_metadata_url(
327-
SCOPE_STEP_UP_INITIAL_SCOPES,
328-
REDIRECT_URI,
329-
Some("conformance-client"),
330-
Some(CIMD_CLIENT_METADATA_URL),
327+
.start_authorization(
328+
AuthorizationRequest::new(REDIRECT_URI)
329+
.with_scopes(SCOPE_STEP_UP_INITIAL_SCOPES.iter().copied())
330+
.with_client_name("conformance-client")
331+
.with_client_metadata_url(CIMD_CLIENT_METADATA_URL),
331332
)
332333
.await?;
333334

@@ -375,11 +376,11 @@ async fn run_auth_scope_step_up_client(
375376

376377
let mut oauth2 = OAuthState::new(server_url, None).await?;
377378
oauth2
378-
.start_authorization_with_metadata_url(
379-
SCOPE_STEP_UP_ESCALATED_SCOPES,
380-
REDIRECT_URI,
381-
Some("conformance-client"),
382-
Some(CIMD_CLIENT_METADATA_URL),
379+
.start_authorization(
380+
AuthorizationRequest::new(REDIRECT_URI)
381+
.with_scopes(SCOPE_STEP_UP_ESCALATED_SCOPES.iter().copied())
382+
.with_client_name("conformance-client")
383+
.with_client_metadata_url(CIMD_CLIENT_METADATA_URL),
383384
)
384385
.await?;
385386
let auth_url2 = oauth2.get_authorization_url().await?;
@@ -427,11 +428,10 @@ async fn run_auth_scope_retry_limit_client(
427428
loop {
428429
let mut oauth = OAuthState::new(server_url, None).await?;
429430
oauth
430-
.start_authorization_with_metadata_url(
431-
&[],
432-
REDIRECT_URI,
433-
Some("conformance-client"),
434-
Some(CIMD_CLIENT_METADATA_URL),
431+
.start_authorization(
432+
AuthorizationRequest::new(REDIRECT_URI)
433+
.with_client_name("conformance-client")
434+
.with_client_metadata_url(CIMD_CLIENT_METADATA_URL),
435435
)
436436
.await?;
437437
let auth_url = oauth.get_authorization_url().await?;

crates/rmcp/src/transport.rs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -99,11 +99,12 @@ pub mod auth;
9999
pub use auth::JwtSigningAlgorithm;
100100
#[cfg(feature = "auth")]
101101
pub use auth::{
102-
AuthClient, AuthError, AuthorizationManager, AuthorizationSession, AuthorizedHttpClient,
103-
ClientCredentialsConfig, CredentialStore, EXTENSION_OAUTH_CLIENT_CREDENTIALS,
104-
InMemoryCredentialStore, InMemoryStateStore, OAuthHttpClient, OAuthHttpClientError,
105-
OAuthHttpClientFuture, OAuthHttpRedirectPolicy, OAuthHttpRequest, ScopeUpgradeConfig,
106-
StateStore, StoredAuthorizationState, StoredCredentials, WWWAuthenticateParams,
102+
AuthClient, AuthError, AuthorizationManager, AuthorizationRequest, AuthorizationSession,
103+
AuthorizedHttpClient, ClientCredentialsConfig, CredentialStore,
104+
EXTENSION_OAUTH_CLIENT_CREDENTIALS, InMemoryCredentialStore, InMemoryStateStore,
105+
OAuthHttpClient, OAuthHttpClientError, OAuthHttpClientFuture, OAuthHttpRedirectPolicy,
106+
OAuthHttpRequest, ScopeUpgradeConfig, StateStore, StoredAuthorizationState, StoredCredentials,
107+
WWWAuthenticateParams,
107108
};
108109

109110
// #[cfg(feature = "transport-ws")]

0 commit comments

Comments
 (0)