clientID, issues credentials, and records redirect URIs before the client can authenticate. This works for a fixed set of applications, but breaks down for the growing population of AI agents and MCP clients that appear dynamically and cannot be pre-provisioned.
Client ID Metadata Documents (CIMD) solve this by letting a client identify itself with an https URL instead of a pre-registered ID. The client’s client_id is a URL that serves a JSON metadata document describing the client. When the Orchestrator receives an authorization request from an unknown URL client_id, it fetches that document, validates it, caches it, and builds a client from it on the fly — no manual registration required. This implements draft-ietf-oauth-client-id-metadata-document.
How it works
An operator enables CIMD by adding one or moreoidcCimd apps to an Orchestrator that already runs an OIDC Provider (the top-level oidcProvider configuration). Each app is a domain-scoped policy: it lists the domains whose metadata URLs it will resolve, and the authentication, authorization, and token settings to apply to clients from those domains.
Once resolved, a CIMD client behaves like any other public or confidential OIDC client: it completes the authorization code flow (with PKCE) and receives tokens signed by the OIDC Provider. Resolved metadata is cached so subsequent requests from the same client skip the fetch.
The metadata document
The document served at theclient_id URL is a JSON object using the client metadata fields defined by OAuth Dynamic Client Registration (RFC 7591) and profiled by draft-ietf-oauth-client-id-metadata-document. Refer to those specifications for the full field registry and semantics.
The Orchestrator reads a subset of those fields — client_id, redirect_uris, grant_types, response_types, token_endpoint_auth_method, jwks_uri, scope, and client_name — and applies the constraints described in Client requirements below.
A minimal metadata document for a public client looks like:
Client requirements
The Orchestrator enforces the following rules. A metadata document that violates any of them makes the client unresolvable, and the authorization request is rejected as an invalid client.client_id URL — must use the https scheme, include a path, and must not contain dot-segments (. / ..), a fragment, userinfo, or a query string. The host must match one of the configured allowedDomains.
redirect_uris — at least one is required. Each must use https, except that http is permitted for loopback hosts (localhost, 127.0.0.1, ::1) per RFC 8252. Loopback redirects may use any port.
grant_types — only authorization_code and refresh_token are supported, and the field defaults to authorization_code when omitted. Declaring refresh_token requires authorization_code as well. Implicit, hybrid, client credentials, and other grants are rejected.
response_types — only code (authorization code flow) is supported, and the field defaults to code when omitted.
token_endpoint_auth_method — defaults to none when omitted:
none— the client is public and MUST use PKCE.private_key_jwt— the client is confidential; itsjwks_urimust be anhttpsURL sharing the same origin (scheme + host + port) as theclient_id. The Orchestrator fetches the JWKS to verify the client’s signed authentication assertions.
scope — optional. When present, requestable scopes are restricted to this set; when omitted, scopes are unrestricted (like a static client).
When a client declares the
refresh_token grant, the Orchestrator automatically grants the offline_access scope so a refresh token is issued — even if the client requests no scope. This is required for agents such as Claude Code that send an empty scope but still need to refresh tokens without re-running the full authorization flow.Configuration
CIMD is configured as one or more apps of typeoidcCimd alongside the top-level oidcProvider configuration. Each oidcCimd app registers a single domain-scoped policy.
| Field | Type | Required | Description |
|---|---|---|---|
allowedDomains | string[] | yes | Domains whose metadata URLs this policy resolves. Each entry is an exact hostname (app.example.com) or a wildcard prefix (*.example.com). A wildcard is only valid as the leftmost label. |
authentication | object | yes | How users are authenticated — an idps list, or isAuthenticatedSE + authenticateSE service extensions. Same shape as an oidc app. |
authorization | object | no | Authorization policy applied to resolved clients. Defaults to allow-all. |
allowedAudiences | string[] | no | Audiences CIMD clients may request in access tokens. |
claimsMapping | map | no | Maps user attributes to token claims, namespaced by connector (e.g. email: azure.email). |
accessToken | object | no | Access token type (jwt / opaque), length, and lifetimeSeconds. |
refreshToken | object | no | Refresh token length and lifetimeSeconds. |
attrProviders | object[] | no | Connectors used to load attributes for resolved clients. |
loadAttrsSE | service extension | no | Customizes attribute loading. |
buildIDTokenClaimsSE | service extension | no | Adds custom claims to the ID token. |
buildAccessTokenClaimsSE | service extension | no | Adds custom claims to the access token. |
Example
An OIDC Provider with a single CIMD policy that resolves any client under*.example.com and authenticates users against an Azure connector:
maverics.yaml
Multiple policies
You can register severaloidcCimd apps to apply different templates to different domains. When more than one policy could match a host, the most specific domain pattern wins: an exact hostname outranks any wildcard, and a wildcard with more labels outranks one with fewer. Exact-duplicate domain strings across policies are rejected at startup.
maverics.yaml
Security and caching
Because the Orchestrator fetches a client-supplied URL, CIMD metadata retrieval is hardened against server-side request forgery (SSRF):- Special-use IP blocking — resolved IPs are checked against RFC 6890 special-use ranges (loopback, private, link-local, etc.) and rejected. The connection is made to the validated IP to prevent DNS rebinding.
- No redirects — the metadata fetch does not follow HTTP redirects.
- Bounded requests — a 5-second timeout and a ~5 KB response size cap, and the response must be
application/json. - Domain allowlist — only hosts matching a policy’s
allowedDomainsare fetched at all.
- The cache TTL is derived from the response’s
Cache-Control: max-age, clamped to a minimum of 5 minutes and a maximum of 24 hours. - Up to 1000 metadata documents are cached per policy.
- When a cached document is refreshed and a security-relevant field changes (
token_endpoint_auth_method,jwks_uri, orredirect_uris), the change is logged.
Discovery
When at least oneoidcCimd policy is registered, the OIDC Provider advertises CIMD support in its discovery (well-known) document:
client_id_metadata_document_supportedis set totrue.token_endpoint_auth_methods_supportedgainsnoneandprivate_key_jwt(the methods CIMD honors) alongside the staticclient_secret_post.
client_id_metadata_document_supported is false.
Examples
The followingoidcCimd app configurations allow common AI clients to authenticate using CIMD without pre-registering a client ID. In each case, the client presents an https URL as its client_id; the Orchestrator matches the host against allowedDomains, fetches the metadata document, and completes the authorization code flow automatically.
- Claude Code / Claude Desktop
- ChatGPT
Both Claude Code and Claude Desktop present a metadata URL on
claude.ai as the client_id. A single oidcCimd policy covers both.maverics.yaml
When Claude Desktop connects via
mcp-remote as a local stdio proxy, CIMD does not apply — the client ID is a plain string, not a URL, and must be registered as a standard OIDC app. See Connect Claude to the Gateway for mcp-remote configuration.Related Pages
Experimental Features
Overview of all experimental features and important caveats
OIDC Provider
Configure the Orchestrator as an OIDC authorization server
AI Identity Gateway
Secure AI agent-to-tool communication via MCP
Connect Claude
Connect Claude Code and other Anthropic clients