Skip to content

Commit 4e36fd9

Browse files
authored
fix: re-register after auth server change (#1011)
1 parent a8308dc commit 4e36fd9

2 files changed

Lines changed: 34 additions & 11 deletions

File tree

conformance/expected-failures-2026-07-28.yaml

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,3 @@ client:
2323
# Auth feature gaps in the 2026-07-28 auth scenarios.
2424
# tracked in #1002
2525
- auth/scope-step-up
26-
# SEP-2352: SDK lacks issuer-stamped credential storage (#879), so the
27-
# sep-2352-reregister-on-as-change check fails.
28-
- auth/authorization-server-migration

crates/rmcp/src/transport/auth.rs

Lines changed: 34 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1088,7 +1088,8 @@ impl AuthorizationManager {
10881088
/// Initialize from stored credentials if available
10891089
///
10901090
/// This will load credentials from the credential store and configure
1091-
/// the client if credentials are found.
1091+
/// the client if credentials are found. Returns `false` when credentials
1092+
/// are absent or discarded after an authorization-server change.
10921093
pub async fn initialize_from_store(&mut self) -> Result<bool, AuthError> {
10931094
if let Some(stored) = self.credential_store.load().await? {
10941095
if stored.token_response.is_some() {
@@ -1133,10 +1134,7 @@ impl AuthorizationManager {
11331134
"authorization server issuer changed; clearing stored credentials bound to the previous issuer"
11341135
);
11351136
self.credential_store.clear().await?;
1136-
return Err(AuthError::AuthorizationServerMismatch {
1137-
expected_issuer: stored_issuer.to_string(),
1138-
received_issuer: current_issuer.to_string(),
1139-
});
1137+
return Ok(false);
11401138
}
11411139
}
11421140

@@ -3549,9 +3547,9 @@ mod tests {
35493547

35503548
use super::{
35513549
AuthError, AuthorizationCallback, AuthorizationManager, AuthorizationMetadata,
3552-
InMemoryStateStore, OAuthClientConfig, OAuthHttpClient, OAuthHttpClientError,
3553-
OAuthHttpClientFuture, OAuthHttpRedirectPolicy, OAuthHttpRequest, ScopeUpgradeConfig,
3554-
StateStore, StoredAuthorizationState, is_https_url,
3550+
CredentialStore, InMemoryCredentialStore, InMemoryStateStore, OAuthClientConfig,
3551+
OAuthHttpClient, OAuthHttpClientError, OAuthHttpClientFuture, OAuthHttpRedirectPolicy,
3552+
OAuthHttpRequest, ScopeUpgradeConfig, StateStore, StoredAuthorizationState, is_https_url,
35553553
};
35563554
use crate::transport::auth::VendorExtraTokenFields;
35573555

@@ -5134,6 +5132,34 @@ mod tests {
51345132
mgr
51355133
}
51365134

5135+
#[tokio::test]
5136+
async fn initialize_from_store_clears_dcr_credentials_when_issuer_changes() {
5137+
let store = InMemoryCredentialStore::new();
5138+
store
5139+
.save(StoredCredentials {
5140+
client_id: "dcr-client".to_string(),
5141+
token_response: Some(make_token_response("old-token", Some(3600))),
5142+
granted_scopes: vec![],
5143+
token_received_at: Some(AuthorizationManager::now_epoch_secs()),
5144+
issuer: Some("https://old.example.com".to_string()),
5145+
})
5146+
.await
5147+
.unwrap();
5148+
let mut manager = manager_with_metadata(Some(AuthorizationMetadata {
5149+
authorization_endpoint: "https://new.example.com/authorize".to_string(),
5150+
token_endpoint: "https://new.example.com/token".to_string(),
5151+
issuer: Some("https://new.example.com".to_string()),
5152+
..Default::default()
5153+
}))
5154+
.await;
5155+
manager.set_credential_store(store.clone());
5156+
5157+
let initialized = manager.initialize_from_store().await.unwrap();
5158+
let credentials_cleared = store.load().await.unwrap().is_none();
5159+
5160+
assert_eq!((initialized, credentials_cleared), (false, true));
5161+
}
5162+
51375163
fn test_client_config() -> OAuthClientConfig {
51385164
OAuthClientConfig {
51395165
client_id: "my-client".to_string(),

0 commit comments

Comments
 (0)