Skip to content

feat: pin OAuth tokens to the canonical MCP resource - #183

Open
mattzcarey wants to merge 1 commit into
mainfrom
feat/strict-oauth-resource
Open

feat: pin OAuth tokens to the canonical MCP resource#183
mattzcarey wants to merge 1 commit into
mainfrom
feat/strict-oauth-resource

Conversation

@mattzcarey

@mattzcarey mattzcarey commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

Summary

Pin OAuth authorization grants, provider-issued access tokens, and direct Cloudflare OAuth credentials to the canonical Cloudflare MCP endpoint.

  • configure an explicit MCP_RESOURCE for local, staging, and production
  • pass that exact endpoint through resourceMetadata.resource
  • require it in authorization and token requests
  • use it as the audience when validating direct Cloudflare OAuth tokens
  • preserve RFC 9207 authorization-response issuer (iss) behavior
  • update the integration suite for exact-resource and PKCE flows

Canonical resources:

  • local: http://localhost:2529/mcp
  • staging: https://staging.mcp.cloudflare.com/mcp
  • production: https://mcp.cloudflare.com/mcp

Validation

  • npm ci
  • npm run check — 19 test files, 256 tests; formatting, lint, types, and tests all pass
  • GitHub CI, CodeQL, and Semgrep all pass

The OAuth integration coverage verifies:

  • protected-resource metadata returns the canonical /mcp resource
  • authorization-server metadata advertises RFC 9207 issuer support
  • successful authorization responses include the expected iss
  • authorization rejects a broader origin resource
  • token exchange rejects an omitted resource without consuming the code
  • retrying that code with the exact resource succeeds
  • direct Cloudflare OAuth credentials use the exact MCP endpoint as their audience

Staging

Deployed to cloudflare-api-mcp-staging:

  • URL: https://staging.mcp.cloudflare.com/mcp
  • Worker version: e0adfb78-5dd9-46cb-928e-9e91f60d7bb3

Deployed metadata, bearer challenge, exact-resource authorization, and rejection of omitted/broader resources were smoke-tested successfully.

Live MCP client E2E

Each client completed browser OAuth against staging, connected to the MCP server, and made a real search tool call that returned { "exists": true }:

Client Version Registration Result
Claude Code 2.1.221 DCR PASS
Codex CLI 0.147.0-alpha.6 DCR PASS
OpenCode 1.14.18 DCR PASS
Pi 0.82.1 with pi-mcp-adapter 2.11.0 DCR PASS

Temporary test registrations, credentials, sessions, and local client configuration were removed after the runs.

Client ID Metadata Documents remain disabled in this PR and are handled in a separate stacked follow-up.

@mattzcarey

Copy link
Copy Markdown
Contributor Author

Post-merge provider verification complete.

I built and packed the exact workers-oauth-provider merge commit 510b20c66a7b9679c73a249ef5e7117aecd9a41a, then ran this consumer's complete suite against it. The merged provider passes 566 tests; this consumer passes all 292 tests against both the packed merge and its locked pkg.pr.new artifact. The installed provider bundle was byte-identical in both cases (dist/oauth-provider.js sha1 2a02d433ad03a91e7f661a496134d05d267d3a60).

Staging was redeployed using the package packed from the merged provider:

  • Version: 97f9f0b3-6b46-410a-af40-43d4a3467c28
  • PRM resource, RFC 9207 metadata, bare bearer challenge, exact-resource admission, and broad/missing-resource rejection all passed
  • temporary DCR smoke state was removed

This validates the intended sequence: merge this consumer PR, release workers-oauth-provider, then replace the preview URL with the released npm version.

@mattzcarey
mattzcarey force-pushed the feat/strict-oauth-resource branch from bacf749 to 0254956 Compare August 4, 2026 21:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant