fix: make CIMD explicitly opt-in via clientIdMetadataDocumentEnabled#158
Merged
mattzcarey merged 9 commits intocloudflare:mainfrom Mar 4, 2026
Merged
Conversation
🦋 Changeset detectedLatest commit: 97ae17c The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
commit: |
…tion CIMD previously auto-enabled when the global_fetch_strictly_public compat flag was present, causing crashes for servers where URL-shaped client_ids hit bot-protected endpoints. This makes CIMD explicitly opt-in and falls through to standard KV lookup when disabled. Closes cloudflare#156
90413de to
9c71716
Compare
When CIMD fetch fails (size limit, timeout, HTTP error, invalid metadata), return null from getClient() so callers treat it as "Invalid client" instead of propagating an unhandled error as a 500. This allows clients like the typescript-sdk to detect the failure and retry with DCR.
When CIMD fetch fails, log a structured warning with host and error category (timeout, network, http_4xx, http_5xx, size_limit, json_parse, metadata_validation) for operator debugging. Log message intentionally excludes error.message to prevent URL leakage. Adds 10 new tests: error logging per category, log sanitization, and token endpoint CIMD failure returning proper invalid_client.
Remove brittle error categorization (string matching). Just log the client URL and error message via console.warn for operator debugging.
Contributor
Author
Tested on stagingDeployed to
Tested with Claude.ai as the client. |
deathbyknowledge
approved these changes
Mar 4, 2026
Merged
mattzcarey
added a commit
to mattzcarey/workers-oauth-provider
that referenced
this pull request
Mar 4, 2026
Add documentation for undocumented options: accessTokenTTL, allowTokenExchangeGrant, clientIdMetadataDocumentEnabled, and resourceMetadata. Rewrite CIMD section to reflect the new opt-in flag added in cloudflare#158.
2 tasks
mattzcarey
added a commit
that referenced
this pull request
Mar 4, 2026
## Summary - Add `accessTokenTTL`, `allowTokenExchangeGrant`, and `clientIdMetadataDocumentEnabled` to the main config example - Add new "Protected Resource Metadata (RFC 9728)" section documenting the `resourceMetadata` option - Rewrite CIMD section to reflect the opt-in flag added in #158 (two-step enablement: option + compat flag) ## Test plan - [x] `npm run check` passes (typecheck + 279 tests) - [ ] Review rendered README on GitHub for formatting
mattzcarey
pushed a commit
that referenced
this pull request
Mar 4, 2026
This PR was opened by the [Changesets release](https://github.com/changesets/action) GitHub action. When you're ready to do a release, you can merge this and the packages will be published to npm automatically. If you're not ready to do a release yet, that's fine, whenever you add more changesets to main, this PR will be updated. # Releases ## @cloudflare/workers-oauth-provider@0.3.0 ### Minor Changes - [#158](#158) [`b26f7ff`](b26f7ff) Thanks [@mattzcarey](https://github.com/mattzcarey)! - Add `clientIdMetadataDocumentEnabled` option to make CIMD (Client ID Metadata Document) support explicitly opt-in. Previously, CIMD auto-enabled when the `global_fetch_strictly_public` compatibility flag was present, which could cause crashes for servers where URL-shaped client_ids hit bot-protected endpoints. When not enabled (the default), URL-formatted client_ids now fall through to standard KV lookup instead of throwing. - [#144](#144) [`49a1d24`](49a1d24) Thanks [@mattzcarey](https://github.com/mattzcarey)! - Add `revokeExistingGrants` option to `completeAuthorization()` that revokes existing grants for the same user+client after creating a new one. Defaults to `true`, fixing infinite re-auth loops when props change between authorizations (issue #34). Set to `false` to allow multiple concurrent grants per user+client. Revoke tokens and grant when an authorization code is reused, per RFC 6749 §10.5. This prevents authorization code replay attacks by invalidating all tokens issued from the first exchange. **Breaking behavior change:** Previously, re-authorizing the same user+client created an additional grant, leaving old tokens valid. Now, old grants are revoked by default. If your application relies on multiple concurrent grants per user+client, set `revokeExistingGrants: false` to preserve the old behavior. ### Patch Changes - [#164](#164) [`4b640a3`](4b640a3) Thanks [@pnguyen-atlassian](https://github.com/pnguyen-atlassian)! - Include `client_secret_expires_at` and `client_secret_issued_at` in dynamic client registration responses when a `client_secret` is issued, per RFC 7591 §3.2.1. - [#165](#165) [`9cce070`](9cce070) Thanks [@mattzcarey](https://github.com/mattzcarey)! - Use `Promise.allSettled` instead of `Promise.all` for best-effort grant revocation in `completeAuthorization()`, ensuring all grants are attempted even if one fails. Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes #156
Three changes to make CIMD (Client ID Metadata Document) robust and explicitly opt-in:
1. Explicit opt-in via
clientIdMetadataDocumentEnabledCIMD previously auto-enabled whenever the
global_fetch_strictly_publiccompatibility flag was present. This caused 500 crashes for servers where URL-shapedclient_ids (e.g.https://claude.ai/oauth/mcp-oauth-client-metadata) hit bot-protected endpoints, since there was no way to disable CIMD independently of the compat flag.clientIdMetadataDocumentEnabled?: booleantoOAuthProviderOptions(defaults tofalse)client_ids fall through to standard KV lookup — no fetch, no crashglobal_fetch_strictly_publicclient_id_metadata_document_supported: trueonly when both the option and compat flag are set2. Graceful CIMD fetch failure handling
When CIMD is enabled and the metadata fetch fails (size limit exceeded, timeout, HTTP error, invalid JSON, network error, metadata validation failure),
getClient()now catches the error and returnsnullinstead of throwing. This means:invalid_clientOAuth error response (HTTP 401), which the typescript-sdk client can catch and retry with DCR3. Structured error logging
CIMD fetch failures are logged via
console.warnwith the client URL and error message, so operators can debug issues without the error propagating as a 500:Usage
Source changes (
src/oauth-provider.ts)clientIdMetadataDocumentEnabledoption toOAuthProviderOptionsgetClient(): new CIMD opt-in gate → KV fallback when disabled; try/catch withconsole.warnwhen enabledclient_id_metadata_document_supportednow requires both option AND compat flagTest plan
console.warnis called with client URL and error details for HTTP failures, timeouts, size limits, and validation failuresinvalid_clientOAuth error (401)clientIdMetadataDocumentEnabled: truestaging.mcp.cloudflare.com) and tested with Claude.ai as client — both CIMD disabled and enabled modes work correctly