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 grants and access tokens to the canonical Cloudflare MCP endpoint.

  • install the preview build from the merged cloudflare/workers-oauth-provider#256
  • configure an explicit MCP_RESOURCE for local, staging, and production deployments
  • pass the configured resource through resourceMetadata.resource
  • require the canonical resource in authorization and token requests
  • update downstream public-client test flows to use PKCE
  • verify RFC 9207 metadata advertisement and the iss value in successful authorization responses
  • update the unauthenticated MCP assertion for the provider's bare bearer challenge

Canonical resources:

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

Dependency and release sequencing

The provider change merged in:

There is intentionally no npm release yet. This PR keeps the pkg.pr.new URL so the consumer can merge first. After this PR merges, release workers-oauth-provider, then replace the preview dependency with the released npm version.

The lockfile pins the preview artifact integrity. I also built and packed the exact merged provider commit; its installed dist/oauth-provider.js was byte-identical to the locked preview artifact (sha1 2a02d433ad03a91e7f661a496134d05d267d3a60).

Tests

Merged provider tree:

  • npm ci
  • npm run check (566 tests)
  • npm run build
  • npx prettier --check .

This consumer, against both the locked preview and a package packed from provider merge commit 510b20c:

  • npm ci
  • npm run check (292 tests)

The OAuth integration suite verifies:

  • protected resource metadata returns the canonical /mcp resource
  • authorization server metadata advertises authorization_response_iss_parameter_supported: true
  • successful authorization redirects include iss=https://mcp.cloudflare.com
  • authorization rejects a broader origin resource
  • token exchange rejects an omitted resource without consuming the code
  • the same code succeeds when retried with the exact resource

Staging

Deployed the consumer branch with a package packed from the exact merged provider commit:

  • Worker: cloudflare-api-mcp-staging
  • URL: https://staging.mcp.cloudflare.com
  • Version: 97f9f0b3-6b46-410a-af40-43d4a3467c28

Deployed checks passed:

  • path-specific protected resource metadata returns https://staging.mcp.cloudflare.com/mcp
  • authorization server metadata reports issuer https://staging.mcp.cloudflare.com
  • metadata advertises authorization_response_iss_parameter_supported: true
  • unauthenticated /mcp returns the bare 401 bearer challenge with the path-specific resource_metadata
  • exact resource=https://staging.mcp.cloudflare.com/mcp reaches consent
  • broader and omitted authorization resources are rejected before consent
  • the temporary DCR smoke-test client was removed from staging KV

@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.

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