Skip to content

Implement SEP-2352: Clarify authorization server binding and migration #879

@alexhancock

Description

@alexhancock

SEP-2352: Clarify authorization server binding and migration — rust-sdk implementation

Spec PR: modelcontextprotocol/modelcontextprotocol#2352
Track: Specification · Stage: accepted · Priority: P0 · Theme: Enterprise Readiness
Needs code changes: Yes (Medium)

Summary

Multi-AS guidance:

  • Clients SHOULD maintain separate registration state per authorization server and MUST NOT assume cross-AS credential validity.
  • New "Authorization Server Binding" rules: DCR / pre-registered credentials must be keyed by issuer; CIMD client_ids are portable; clients should error on AS mismatch.

Why this needs code changes in rust-sdk

The OAuth client in crates/rmcp/src/transport/auth.rs persists credentials and registration state
via the CredentialStore trait (StoredCredentials, InMemoryCredentialStore) and the
StateStore trait (StoredAuthorizationState, InMemoryStateStore). Today these are effectively
single-AS: StoredCredentials and the in-memory stores are not keyed by issuer, and
AuthorizationManager holds one metadata: Option<AuthorizationMetadata> (whose issuer field
exists but isn't used to partition stored credentials). So credentials from one AS could be reused
against another, which SEP-2352 forbids.

Proposed work

  • Key CredentialStore / StateStore entries by issuer — either add an issuer discriminator to StoredCredentials / load/save keys, or make the in-memory stores HashMap<issuer, …> so per-AS state is isolated.
  • On token use, compare the active AuthorizationMetadata.issuer against the issuer the stored credentials were minted for; on mismatch return a clear AuthError (add a variant, e.g. AuthError::AuthorizationServerMismatch).
  • Treat CIMD client_ids as portable (don't tie those to a single issuer), but keep DCR/pre-registered credentials issuer-bound.
  • Update register_client / configure_client_id / get_credentials paths to read/write the issuer-keyed store.
  • Add tests: two ASes with distinct registrations don't cross-contaminate; mismatch is rejected.

Affected areas

crates/rmcp/src/transport/auth.rs (CredentialStore/StoredCredentials, StateStore/StoredAuthorizationState, InMemory*Store, AuthorizationManager, AuthError).

Notes / risks

  • Part of the Enterprise Readiness auth cluster (837, 2350, 2351, 2468). Bundle into one auth PR/effort to share test scaffolding.

Metadata

Metadata

Assignees

No one assigned

    Labels

    P2Medium: important but non-blocking improvementT-enhancementNew features and enhancementsT-securitySecurity-related changesT-transportTransport layer changes

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions