Skip to content

refactor(auth): resolve Cloudflare credentials through OAuth provider - #185

Draft
mattzcarey wants to merge 6 commits into
mainfrom
feat/external-api-token-resolution
Draft

refactor(auth): resolve Cloudflare credentials through OAuth provider#185
mattzcarey wants to merge 6 commits into
mainfrom
feat/external-api-token-resolution

Conversation

@mattzcarey

@mattzcarey mattzcarey commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

Summary

Move direct Cloudflare bearer credentials behind workers-oauth-provider's resolveExternalToken hook.

The provider now owns bearer parsing, internal MCP access-token lookup, request dispatch, no-store error responses, and RFC 6750/9728 challenges. Our resolver runs only when the provider does not find one of its own tokens.

Direct credential behavior

The resolver uses the credential prefix as an ownership hint, following cloudflare/mcp-server-cloudflare#393:

  • cfat_: query one minimum-size /accounts?per_page=5 page and require exactly one account
  • cfut_: query /user and /accounts in parallel and require a user
  • cfoat_: same user-owned path, including Wrangler OAuth credentials
  • unprefixed legacy credentials: keep the existing two-probe response-based fallback

The resolver produces a discriminated identity (account or user) before building request props, so impossible combinations such as a null user with an arbitrary account list cannot cross the boundary. The existing token-hash identity cache remains. Its namespace moves to v4 for the new shape, and cached values are validated with the same Zod schema before use.

Expected validation failures are converted to the provider's ExternalTokenError:

  • malformed or invalid credentials return 401 invalid_token
  • missing identity permissions return 403 insufficient_scope with owner-specific scope guidance
  • rate limits preserve 429 and Retry-After
  • upstream failures return 502 server_error
  • unexpected application errors still escape as Worker failures instead of being mislabeled as bad credentials

The Cloudflare OAuth authorization and refresh implementation is unchanged. Provider-issued MCP access tokens resolve internally and do not call the external resolver.

Provider release dependency

This currently pins the official pkg.pr.new build from cloudflare/workers-oauth-provider#272 because npm 0.8.3 does not export ExternalTokenError.

cloudflare/workers-oauth-provider#261 will publish these merged changes as 0.9.0. Before this PR is marked ready, replace the preview URL with exact 0.9.0 and refresh the lockfile.

The provider upgrade also requires public OAuth clients to use PKCE and returns a bare challenge when credentials are missing. The OAuth route tests were updated for those released behaviors, without changing our upstream OAuth flow.

Compliance note

Direct Cloudflare API token support remains an explicit compatibility mode. It does not make an upstream Cloudflare credential an MCP-issued access token. OAuth remains the recommended MCP authorization path. This change makes compatibility-mode validation and error handling consistent with the provider and OAuth resource-server semantics.

Validation

  • npm ci
  • npm run check (19 files, 295 tests)
  • targeted oxfmt and oxlint checks for changed tests
  • npx wrangler deploy --dry-run --env staging
  • npm audit --omit=dev reports the existing Hono advisory, unrelated to this change

@mattzcarey
mattzcarey force-pushed the feat/external-api-token-resolution branch from 9fdfeb9 to 6f23438 Compare July 30, 2026 23:37
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