|
| 1 | +--- |
| 2 | +id: client-id-metadata-document |
| 3 | +title: Use client ID metadata documents |
| 4 | +sidebar_label: Client ID metadata |
| 5 | +slug: client-id-metadata-document |
| 6 | +--- |
| 7 | + |
| 8 | +## Overview |
| 9 | + |
| 10 | +Client ID Metadata Document (CIMD) lets Hydra treat a `client_id` as an HTTPS URL that points to a metadata document. Hydra |
| 11 | +fetches that document to populate client settings such as redirect URIs, token endpoint auth method, and JWKS. The feature follows |
| 12 | +the draft OAuth Client ID Metadata Document specification. See the current draft for details in the |
| 13 | +[IETF document](https://datatracker.ietf.org/doc/draft-ietf-oauth-client-id-metadata-document/). |
| 14 | + |
| 15 | +CIMD modes control acceptance of URL-based client identifiers: |
| 16 | + |
| 17 | +- `disabled`: CIMD is off and Hydra only accepts string or UUID client IDs (default). |
| 18 | +- `optional`: Hydra accepts both URL client IDs and non-URL client IDs (typical starting point). |
| 19 | +- `enforced`: Hydra only accepts URL client IDs. |
| 20 | + |
| 21 | +Discovery stays disabled by default. Enabling CIMD does not expose discovery unless you also enable discovery in your deployment. |
| 22 | + |
| 23 | +## Enable CIMD in Hydra |
| 24 | + |
| 25 | +1. Upgrade Hydra to a build that includes CIMD and apply the accompanying migrations. |
| 26 | +2. In the Hydra configuration, enable CIMD and pick the mode: |
| 27 | + |
| 28 | + ```yaml |
| 29 | + oauth2: |
| 30 | + client_id_metadata_document: |
| 31 | + enabled: true |
| 32 | + mode: optional # disabled | optional | enforced |
| 33 | + cache: |
| 34 | + min_ttl: 5m |
| 35 | + max_ttl: 30m |
| 36 | + http: |
| 37 | + timeout: 5s |
| 38 | + max_size: 1048576 # bytes |
| 39 | + clients: |
| 40 | + http: |
| 41 | + disallow_private_ip_ranges: true |
| 42 | + private_ip_exception_urls: |
| 43 | + - https://metadata.example.internal/client.json |
| 44 | + ``` |
| 45 | +
|
| 46 | +3. Adjust HTTP safety limits to match your environment: |
| 47 | + - `oauth2.client_id_metadata_document.http.timeout` controls the metadata fetch timeout. |
| 48 | + - `oauth2.client_id_metadata_document.max_size` rejects responses larger than this value. |
| 49 | + - `clients.http.disallow_private_ip_ranges` blocks metadata fetches to private networks. Add allowed hosts to |
| 50 | + `clients.http.private_ip_exception_urls` when needed. |
| 51 | +4. Set cache bounds with `oauth2.client_id_metadata_document.cache.min_ttl` and `oauth2.client_id_metadata_document.cache.max_ttl` |
| 52 | + to avoid over-fetching while keeping metadata fresh. |
| 53 | +5. Enable discovery only if you want to expose CIMD through the well-known endpoint. CIMD works without discovery. |
| 54 | + |
| 55 | +## Configuration reference |
| 56 | + |
| 57 | +Use these configuration keys to control CIMD behavior. Defaults are shown for reference; confirm them against your release. |
| 58 | + |
| 59 | +- `oauth2.client_id_metadata_document.enabled`: Enables CIMD feature. Default: `false`. |
| 60 | +- `oauth2.client_id_metadata_document.mode`: `disabled` | `optional` | `enforced`. Default: `disabled`. |
| 61 | +- `oauth2.client_id_metadata_document.cache.min_ttl`: Minimum cache TTL for fetched metadata. Default: `5m`. |
| 62 | +- `oauth2.client_id_metadata_document.cache.max_ttl`: Maximum cache TTL for fetched metadata. Default: `24h`. |
| 63 | +- `oauth2.client_id_metadata_document.http.timeout`: HTTP client timeout for CIMD fetches. Default: `5s`. |
| 64 | +- `oauth2.client_id_metadata_document.max_size`: Maximum response body size for a metadata fetch. Default: `5KB`. |
| 65 | +- `clients.http.disallow_private_ip_ranges`: Enforces SSRF protection by disallowing private IP ranges. Default: project-global |
| 66 | + setting. |
| 67 | +- `clients.http.private_ip_exception_urls`: Explicit allowlist entries when private IP ranges are disallowed. |
| 68 | + |
| 69 | +## Discovery and well-known exposure |
| 70 | + |
| 71 | +Hydra serves `.well-known/openid-configuration` and `.well-known/oauth-authorization-server` by default. CIMD-specific fields |
| 72 | +appear in those documents only when CIMD is enabled. If CIMD is disabled, the well-known responses remain unchanged. |
| 73 | + |
| 74 | +When CIMD is enabled, Hydra adds details to the discovery documents: |
| 75 | + |
| 76 | +- Indicates CIMD support (for example, as a capability entry alongside other Hydra extensions). |
| 77 | +- States that `client_id` can be an HTTPS URL referencing a metadata document when `mode` is `optional`, and must be when `mode` |
| 78 | + is `enforced`. |
| 79 | +- Notes JWKS requirements for `private_key_jwt` clients (publish `jwks` or `jwks_uri`). |
| 80 | +- Explains CORS validation uses resolved metadata, so URL-based `client_id` values participate in CORS decisions. |
| 81 | +- Documents security constraints: HTTPS-only, path required, no fragment, SSRF and allowlist enforcement, timeout, and maximum |
| 82 | + response size limits. |
| 83 | +- Mentions metadata caching with minimum and maximum TTLs; exact values remain deployment-specific unless you choose to expose |
| 84 | + them. |
| 85 | + |
| 86 | +Discovery visibility is separate from operational behavior. Fetching and validation follow `enabled`, `mode`, and the safety |
| 87 | +limits above, regardless of whether discovery is exposed. |
| 88 | + |
| 89 | +## Prepare the client metadata document |
| 90 | + |
| 91 | +Publish a client metadata document at the HTTPS URL you plan to use as `client_id`. The URL must use HTTPS, include a path, and |
| 92 | +omit fragments. The document must satisfy these rules: |
| 93 | + |
| 94 | +- Provide `redirect_uris` that follow RFC 8252 rules. Loopback and `localhost` redirects are allowed per the specification. |
| 95 | +- For `private_key_jwt` clients, include `jwks` or `jwks_uri` so Hydra can validate assertions. |
| 96 | +- Include the token endpoint auth method in `token_endpoint_auth_method` when the client is not using the default |
| 97 | + `client_secret_basic`. |
| 98 | +- Keep the document within the configured `max_size` and ensure the server responds within the configured timeout. |
| 99 | + |
| 100 | +Example document: |
| 101 | + |
| 102 | +```json |
| 103 | +{ |
| 104 | + "redirect_uris": ["https://app.example.com/callback", "http://localhost:8080/callback"], |
| 105 | + "token_endpoint_auth_method": "private_key_jwt", |
| 106 | + "jwks": { |
| 107 | + "keys": [ |
| 108 | + { |
| 109 | + "kty": "RSA", |
| 110 | + "kid": "client-key-1", |
| 111 | + "e": "AQAB", |
| 112 | + "n": "...base64-modulus..." |
| 113 | + } |
| 114 | + ] |
| 115 | + }, |
| 116 | + "client_name": "Example CIMD client" |
| 117 | +} |
| 118 | +``` |
| 119 | + |
| 120 | +## How CIMD works at runtime |
| 121 | + |
| 122 | +When Hydra receives a `client_id` that is a valid HTTPS URL, it fetches the metadata document and applies these checks: |
| 123 | + |
| 124 | +- Enforces HTTPS, rejects URLs without a path, and rejects URLs that include fragments. |
| 125 | +- Applies SSRF protections using `clients.http.disallow_private_ip_ranges` and `clients.http.private_ip_exception_urls`. |
| 126 | +- Honors `oauth2.client_id_metadata_document.http.timeout` and `oauth2.client_id_metadata_document.max_size`. |
| 127 | +- Validates redirect URIs against RFC 8252 rules. |
| 128 | +- Requires JWKS or `jwks_uri` for `private_key_jwt` clients. |
| 129 | + |
| 130 | +A successful fetch populates the client settings and records `client_id_metadata_fetched_at`. Cache TTLs from the CIMD |
| 131 | +configuration prevent repeated fetches; subsequent requests reuse cached metadata until the TTL expires. Concurrent fetches for |
| 132 | +the same URL are safe. |
| 133 | + |
| 134 | +CORS, device flow, logout, and token handlers rely on the same client lookup logic, so URL-based `client_id` values work across |
| 135 | +those paths. |
| 136 | + |
| 137 | +## Operate and verify |
| 138 | + |
| 139 | +- Default behavior does not change until `oauth2.client_id_metadata_document.enabled` is set to `true`. |
| 140 | +- If you set `mode` to `enforced`, Hydra rejects non-URL client IDs. |
| 141 | +- Keep cache TTLs aligned with how often client operators update their metadata documents. |
| 142 | +- If you disallow private IP ranges, configure exception URLs for trusted metadata hosts before enabling CIMD for those clients. |
| 143 | +- Run your CI or staging environment with timeouts and maximum size values that match production to catch oversized or slow |
| 144 | + metadata responses early. |
| 145 | + |
| 146 | +## Test the setup |
| 147 | + |
| 148 | +Use these checks in your deployment tests: |
| 149 | + |
| 150 | +- Verify a URL `client_id` is accepted when CIMD is `optional` and rejected when CIMD is `disabled`. |
| 151 | +- Confirm Hydra rejects metadata fetches that exceed the configured timeout or maximum size. |
| 152 | +- Verify SSRF protections by confirming requests to private IP ranges fail unless listed in |
| 153 | + `clients.http.private_ip_exception_urls`. |
| 154 | +- Confirm `private_key_jwt` clients are rejected when the metadata document omits `jwks` or `jwks_uri`. |
| 155 | +- Run auth, token, device, and logout flows with URL `client_id` values to confirm end-to-end behavior. |
| 156 | +- If you enable discovery, verify the well-known endpoint reflects CIMD as expected. |
0 commit comments