Skip to content

Support OAuth Client ID Metadata Documents (CIMD)#5

Merged
wille merged 1 commit into
masterfrom
cimd-support
Jul 6, 2026
Merged

Support OAuth Client ID Metadata Documents (CIMD)#5
wille merged 1 commit into
masterfrom
cimd-support

Conversation

@wille

@wille wille commented Jul 6, 2026

Copy link
Copy Markdown
Owner

Summary

Implements OAuth Client ID Metadata Documents: clients use an HTTPS URL as their client_id, and the authorization server fetches and validates a JSON metadata document from that URL instead of requiring registration.

The draft MCP Authorization spec says authorization servers SHOULD support CIMD and deprecates Dynamic Client Registration in its favor. Claude clients (Web, Desktop, Code, Cowork) now use CIMD exclusively for user-initiated MCP OAuth flows, and ChatGPT prefers it when advertised - both select CIMD when the metadata advertises client_id_metadata_document_supported: true alongside none in token_endpoint_auth_methods_supported, which this server does. The upstream MCP SDK only implements the client side, so this is original AS-side work following the spec.

Usage

Opt-in on OAuthServer (off by default since it makes the server fetch client-supplied URLs):

const oauthServer = new OAuthServer({
    clientIdMetadataDocuments: true, // or ClientIdMetadataDocumentOptions
    // ...
});

Implementation

  • isClientIdMetadataDocumentUrl() detects URL-formatted client ids (HTTPS, path component, no fragment/credentials); OAuthServer.getClient() resolves them via the new ClientIdMetadataDocumentFetcher, so the authorize, token, refresh, revoke, and device flows work with URL client ids unchanged.
  • Spec MUSTs enforced: document client_id equals the URL exactly; valid JSON with required client_id, client_name, redirect_uris; redirect URIs validated against the document by the existing handlers.
  • CIMD clients are public clients: documents demanding any token_endpoint_auth_method other than none are rejected (private_key_jwt not supported), and grant_types must be enabled on the server.
  • Caching goes through the OAuthServerModel via new optional saveClientIdMetadataDocument / getClientIdMetadataDocument methods (implemented by MemoryOAuthServerModel), honoring Cache-Control (max-age clamped to a configurable ceiling, no-store/no-cache uncached) - instances sharing a model share the cache. Enabling CIMD on a model lacking these methods fails at construction, matching the device-grant capability check.
  • SSRF posture: HTTPS only, no redirects, 5s timeout, 10 KB size cap, loopback/IP-literal hosts always rejected, plus a validateClientIdUrl trust-policy hook (e.g. domain allowlists) and injectable fetch. DNS-rebinding protection is explicitly out of scope and documented.
  • Metadata advertises client_id_metadata_document_supported: true only when enabled.

Docs

README gained a CIMD section (usage, trust policy, security notes including the localhost-redirect impersonation caveat for consent screens), DCR is marked as deprecated by the MCP spec in favor of CIMD (kept for backwards compatibility), and the spec-compliance list was refreshed to name everything implemented (PKCE/RFC 7636, RFC 6750, RFC 8707).

Tests

28 new tests: URL detection, document validation failures (mismatched client_id, missing fields, invalid JSON, HTTP errors, oversized), SSRF and trust-hook rejections, model-backed caching (cache hit, no-store, max-age expiry, cache shared across server instances), server-config validation, metadata advertisement, and an authorize-flow round trip with a URL client id - all with injected mock fetch, no network.

Clients can use an HTTPS URL as their client_id; the server fetches and
validates the metadata document from that URL per
draft-ietf-oauth-client-id-metadata-document-00. Opt-in via the
clientIdMetadataDocuments option. Documents are cached through the
OAuthServerModel (saveClientIdMetadataDocument /
getClientIdMetadataDocument) respecting Cache-Control headers.

The draft MCP Authorization spec recommends CIMD and deprecates Dynamic
Client Registration in its favor.
@wille
wille merged commit 890f4fc into master Jul 6, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant