Skip to content

OAuth / MCP client registration: DCR (public + confidential) now, CIMD next ​

Status: Accepted — DCR (public + confidential) shipped (PR #68, 348a8d0); CIMD adopted as the preferred future direction, implementation pending (design phase) · Decided: 2026-06-13

Context ​

Modgud is an OAuth 2.1 / OIDC IdP whose primary near-term clients are MCP connectors (claude.ai, ChatGPT / OpenAI Apps SDK, likely Microsoft Copilot). These clients self-onboard — nobody pre-registers each one by hand. Two mechanisms exist:

  • RFC 7591 Dynamic Client Registration (DCR): the client POSTs to /connect/register; the server mints a client_id (and optionally a secret) and stores a client record.
  • Client ID Metadata Document (CIMD): the client_id is an HTTPS URL pointing to a JSON metadata document the server fetches on demand — no stored record, no open registration endpoint. draft-ietf-oauth-client-id-metadata-document (Parecki/Smith, adopted by the IETF OAuth WG Oct 2025); MCP made CIMD the preferred default over DCR. Both claude.ai and ChatGPT support it.

DCR v1 accepted only public PKCE clients (token_endpoint_auth_method = none). But claude.ai's connector registers confidential (client_secret_post / client_secret_basic) and was rejected with InvalidTokenAuthMethod — observed directly in the production audit log. MCP clients fall back to DCR when CIMD isn't advertised, so DCR must accept confidential.

Decision ​

  1. DCR accepts public AND confidential clients (none, client_secret_basic, client_secret_post). A secret-based method → Confidential client with a server-generated, hashed secret returned once per RFC 7591 §3.2.1. private_key_jwt is not accepted via DCR (no JWKS intake in the request shape) → rejected with a hint to pre-register. (Shipped, PR #68.)
  2. Discovery advertises none in token_endpoint_auth_methods_supported so the metadata reflects the public clients the server actually supports (OpenIddict emits only confidential methods by default). (Shipped, PR #68.)
  3. CIMD is the chosen primary path going forward, with DCR (now public + confidential) kept as the fallback — mirroring what Anthropic and OpenAI do ("prefer CIMD, fall back to DCR"). (Accepted direction; not yet implemented.)

Rationale ​

  • DCR-confidential is the immediate unblocker for the real, observed client (claude.ai) and is low-risk — it reuses the existing admin secret-mint + hash path.
  • CIMD is more secure and more future-proof: no open registration endpoint (removes the "any stranger can mint client records" surface), no client secrets at rest, and identity bound to domain ownership (the metadata-URL origin must match the client_id). It is IETF-standardised, MCP-preferred and multi-vendor — so investing in it serves every future MCP client, not just one.
  • Keeping DCR as the fallback means clients / AS setups without CIMD still work.

Alternatives considered (and rejected) ​

  • Public-PKCE-only DCR (the v1 profile): rejected — claude.ai (and the MCP confidential pattern) can't register; discovery also advertised confidential methods, contradicting the policy.
  • Confidential-only / drop public: rejected — public PKCE clients are legitimate and must keep working.
  • Drop DCR, CIMD-only: rejected — DCR is still needed as a fallback for clients/servers without CIMD; the vendors themselves keep DCR as fallback.
  • CIMD first (before confidential DCR): rejected for sequencing — CIMD is a substantial build (custom OpenIddict integration for URL client_ids + an SSRF-hardened fetcher + caching); confidential-DCR unblocks the real client now while CIMD is designed.

Consequences ​

  • Positive: claude.ai / ChatGPT can self-register today; the forward path (CIMD) is the standardised, more secure one.
  • Security to watch: DCR is an open registration endpoint (rate-limited + reserved-name-guarded, but still mints records on demand) — CIMD removes this surface. CIMD introduces a new surface: the server fetches a client-controlled URL → SSRF must be hardened (HTTPS-only; block private/loopback/link-local; no internal redirects; size + timeout limits; caching with TTL; origin-match validation).
  • Follow-up: a dedicated ADR + design will cover the CIMD implementation (OpenIddict integration approach, the hardened fetcher, discovery field client_id_metadata_document_supported: true, caching/revocation, tests).

References ​

  • PR #68 348a8d0 — confidential DCR + discovery none.
  • Code: Modgud.Application/Dcr/ (validator), Modgud.Api/Features/Auth/OAuth/DcrRegistrationEndpoints.cs, Modgud.Infrastructure/OpenIddict/TokenEndpointAuthMethodsSupportedHandler.cs.
  • docs/admin/dynamic-client-registration.md — DCR v1 (2026-05).
  • IETF draft-ietf-oauth-client-id-metadata-document (OAuth WG, adopted Oct 2025); MCP authorization spec (modelcontextprotocol.io).

Released under the Apache-2.0 License.