Skip to content

client_credentials (2/4): CIMD-first client resolution for private_key_jwt agents (DCR back-compat optional) #161

Description

@heskew

Part 2 of 4 for #159 (see the design review). Re-scoped 2026-07-09: CIMD-first, DCR demoted to optional back-compat — the MCP draft spec marks DCR deprecated and CIMD SHOULD-support (#166), and #167 explicitly defers private_key_jwt activation to this work. The original "extend DCR + initialAccessToken gate" plan solved a problem CIMD dissolves: agents don't register — the fleet hosts a metadata document per agent (client_id = its HTTPS URL) carrying the Ed25519 JWKS.

Scope

Client resolution & validation (builds on #167's resolveClient() / shared clientValidator):

  • Accept CIMD documents describing headless agents: grant_types: ["client_credentials"], token_endpoint_auth_method: "private_key_jwt", jwks = JWK Set of public OKP/Ed25519 keys only (reject any key carrying private d; reject empty sets and non-OKP/Ed25519 keys).
  • Conditional shape for client_credentials-only clients: no redirect_uris, no response_types. ⚠️ Spec check at implementation time: the CIMD draft's required-fields list includes redirect_uris — confirm whether non-interactive clients have a carve-out or document our deviation explicitly.
  • Reject client_credentials combined with refresh_token.

Gate (security-critical): for client_credentials via CIMD, clientIdMetadataDocuments.allowedHosts MUST be configured and the client_id URL's host MUST match — merely hosting a reachable document must never suffice to mint tokens. Fail closed (config error) when the grant is enabled without an allowlist. (This replaces the re-scoped-away initialAccessToken DCR gate; enforcement is server-side policy, not document self-assertion.)

Key rotation / revocation semantics: document cache-TTL-bounded staleness — pulling a fleet key from the document takes effect within the CIMD cache TTL; bounded further by the ≤60s assertion window + short access-token TTL. Belongs in the threat notes, not new mechanism.

DCR back-compat (optional, may drop from v1): since validators are shared, DCR registration of private_key_jwt clients may come nearly free — if kept, the original initialAccessToken-required gate applies. Not required for the Flair fleet path.

Tests

CIMD document for a client_credentials agent resolves and validates (valid Ed25519 JWK Set); private-d / RSA / empty jwks rejected; missing-allowlist fails closed; off-allowlist document host rejected; client_credentials+refresh_token rejected; redirect_uris still required for interactive clients; interactive CIMD clients unaffected.

Dependencies

#167 (CIMD resolution layer) and #160 (merged). #162 depends on this. Small enough that folding into #162 is a fair call for whoever implements.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Fields

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