Cloudflare Workers OAuth Provider

repository·main·Indexed 23 days ago

https://github.com/cloudflare/workers-oauth-provider

An OAuth 2.1 Provider Framework designed for Cloudflare Workers. It supports modern standards including PKCE, Dynamic Client Registration (DCR), and Model Context Protocol (MCP) authorization. The library provides the OAuthProvider class to manage authorization flows, token lifecycle, and protected resource metadata (RFC 9728), utilizing Cloudflare Workers KV for storage.

Tokens
22.2K
Snippets
34
Records
87
Agent score
82%

What's inside @cloudflare/workers-oauth-provider

  1. Understand the MCP authorization conformance test suite architecture

    main

    The conformance suite is designed to test the OAuthProvider implementation against MCP (Model Context Protocol) authorization requirements. The test architecture is composed of several key components:

    • Deployable Fixture: worker/index.ts hosts the OAuthProvider within a Worker environment.
    • Configuration: worker/wrangler.jsonc manages Worker configuration and local KV bindings.
    • Test Harness: support/harness.ts manages the workerd lifecycle and ensures per-test storage resets.
    • Client Implementation: support/oauth-client.ts provides an OAuth-specific HTTP client for executing tests.
    • Shared Logic: shared.ts contains RPC configurations, credential types, and fixture constants.

    Tests are organized by functional area:

    • Authorization Server: Metadata and authorization-code/PKCE flows.
    • Authorization Security: Redirects, client authentication, Resource Indicators, issuer, and refresh-scope security.
    • Protected Resource: RFC 9728 discovery, Bearer challenges, scopes, and audience enforcement.
    • Client Registration: Dynamic Client Registration (DCR), pre-registration, and Client ID Metadata Documents (CIMD).
    • Token Lifecycle: Refresh, downscoping, code replay, and revocation.

    Note: Application-owned identity, consent presentation, and operation-level authorization policy are not covered by this conformance suite as they reside outside the provider's scope.

  2. Manage Resources and Token Audiences

    main

    The provider uses RFC 8707 resource indicators. MCP clients should send the canonical MCP server URI as the resource in authorization and token requests.

    Resource Policy via resourceMetadata.resource:

    • When configured: Authorization requests, token requests, and externally resolved tokens must use that exact resource.
    • When omitted: Valid resources are accepted. If the authorization request omits the resource, the provider uses the request origin as the default, issuing an origin-bound token.

    Path-aware Audiences: Audiences use path-boundary prefix matching. For example, a token for https://example.com/mcp is valid at /mcp/tools but invalid at /mcp-other.

    Note: resourceMatchOriginOnly is a legacy migration option for grants created before path-aware resources. Do not enable it for new deployments.

  3. Standards supported by workers-oauth-provider

    main

    The @cloudflare/workers-oauth-provider package implements or supports several key OAuth 2.1 and Model Context Protocol (MCP) standards, including:

    • MCP Authorization (2026-07-28 specification)
    • OAuth 2.1 (draft-ietf-oauth-v2-1-13)
    • OAuth 2.0 Bearer Token Usage (RFC 6750)
    • OAuth 2.0 Token Revocation (RFC 7009)
    • OAuth 2.0 Dynamic Client Registration (RFC 7591)
    • Proof Key for Code Exchange (PKCE) (RFC 7636)
    • OAuth 2.0 Authorization Server Metadata (RFC 8414)
    • OAuth 2.0 Token Exchange (RFC 8693)
    • Resource Indicators for OAuth 2.0 (RFC 8707)
    • OAuth 2.0 Authorization Server Issuer Identification (RFC 9207)
    • OAuth 2.0 Protected Resource Metadata (RFC 9728)
    • OAuth Client ID Metadata Documents
    • MCP Enterprise-Managed Authorization (with experimental package support)
  4. Security model for sensitive data in OAUTH_KV

    main

    The library follows a strict security model to ensure that even if KV storage is compromised, sensitive data remains protected:

    1. Hashing: Access tokens, refresh tokens, client secrets, and authorization codes are all stored as SHA-256 hashes. Only the hash is stored; the plaintext is never saved.
    2. PKCE: For Proof Key for Code Exchange, only the codeChallenge is stored; the code_verifier is never stored.
    3. End-to-End Encryption for Props:
      • Each grant has a unique AES-256 key for encrypting props using AES-GCM.
      • The encryption key is wrapped (using AES-KW) with the token itself.
      • This means only a holder of the valid token can unwrap the key and decrypt the properties. No backup of the encryption key exists.
    4. Key Wrapping: Token wrapping keys are derived using HMAC-SHA256 with a static key, ensuring security separation from token ID generation.
  5. Test architecture and environment

    main

    The conformance tests are executed using a real Wrangler project managed via Cloudflare's createTestHarness() API. The tests run in workerd with the following environment configuration:

    • Storage: A local OAUTH_KV namespace using the actual Workers KV binding API.
    • Compatibility: The global_fetch_strictly_public compatibility flag is enabled to support CIMD.
    • Handlers:
      • An application-owned authorization handler that grants synthetic consent.
      • A protected /mcp handler that exposes only authenticated properties.
    • Resource: The canonical resource https://mcp.example.com/mcp is used for testing Resource Indicator requirements.
    • Client: support/oauth-client.ts provides a typed OAuth HTTP client that can switch between a backwards-compatible profile and a strict canonical-resource profile.

    Tests are black-box: they assert only observable HTTP responses, redirects, metadata, challenges, and token behavior, without accessing provider internals.

  6. Manage Scopes and Step-up Authorization

    main

    The provider publishes scopesSupported in the authorization server metadata. You should configure resourceMetadata.scopes_supported with the minimal scopes required for baseline functionality.

    Granting Scopes: Your application decides which requested scopes to grant using completeAuthorization({ scope }). Note that subsequent token and refresh requests can only narrow (not expand) these scopes.

    Enforcement:

    • The provider does not enforce operation-level scope policy in API handlers.
    • It provides baseline scope guidance in Bearer challenges via protected resource metadata.
    • For advanced needs, you can provide operation-specific step-up guidance through external-token validation.
  7. How MCP authorization discovery works

    main

    MCP (Model Context Protocol) clients discover authorization via a two-stage process:

    1. Challenge: The client sends an unauthenticated request to a protected endpoint (e.g., /mcp). The provider responds with 401 Unauthorized and a WWW-Authenticate header containing the resource_metadata URL.
    2. Resource Metadata: The client fetches the metadata from /.well-known/oauth-protected-resource/mcp (or the path specified in the challenge). This document identifies the authorization_servers.
    3. Server Metadata: The client then fetches the RFC 8414 authorization server metadata from the identified issuer (e.g., /.well-known/oauth-authorization-server) to find the authorization_endpoint, token_endpoint, and other capabilities.

    Metadata Roles

    • Protected Resource Metadata: Describes the MCP server and points to its authorization servers.
    • Authorization Server Metadata: Describes OAuth endpoints and capabilities (PKCE, CIMD, etc.).
  8. Understand MCP authorization conformance coverage

    main

    The conformance suite tests the OAuthProvider against multiple dated revisions of the MCP specification (from 2025-03-26 to 2026-07-28). It exercises shared OAuth behavior across all revisions, using the MCP-Protocol-Version header to signal the target revision.

    Key areas of coverage include:

    • Metadata & Discovery: Authorization server metadata (RFC 8414), Protected Resource Metadata (RFC 9728), and Client ID Metadata Documents (CIMD).
    • OAuth Flows: Authorization code flow for public and confidential clients, and S256 PKCE enforcement.
    • Client Management: Dynamic Client Registration (DCR) and pre-registered clients.
    • Token & Security: Token endpoint authentication (client_secret_basic, client_secret_post), refresh token rotation, revocation (RFC 7009), and Bearer challenges (RFC 6750).
    • Resource Indicators: RFC 8707 Resource Indicators and audience validation (for revisions 2025-06-18 and later).
    • Advanced Scenarios: Authorization response issuer advertisement (RFC 9207) and insufficient_scope challenges for step-up operations.
  9. Understand the OAuth KV Storage Workflow

    main

    The provider uses Cloudflare KV to manage the lifecycle of clients, grants, and tokens. The workflow follows these stages:

    1. Client Registration: Creates a client:{clientId} entry with a hashed client secret.
    2. User Authorization: Creates a grant:{userId}:{grantId} entry. This entry includes a hashed authorization code, PKCE details (if applicable), and an encrypted props object. The encryption key for props is wrapped using the authorization code and stored in authCodeWrappedKey.
    3. Token Exchange: The client exchanges the code for tokens. The system validates the code, PKCE, and client ID. The encryption key is unwrapped using the code and re-wrapped for the new access and refresh tokens. The grant is updated to remove authCodeWrappedKey (marking the code as used) and the refreshTokenId is set. The grant's TTL is removed to make it permanent.
    4. API Request: The system uses the structured key token:{userId}:{grantId}:{accessTokenId} to find the token, unwraps the encryption key using the access token, and decrypts the props for the API handler.
    5. Token Expiration: Access tokens expire via KV TTL. Refresh tokens expire based on refreshTokenTTL (default: 30 days). The provider rotates refresh tokens on every use.
    6. Revocation: Revoking a grant or deleting a client cascades deletions. Deleting a client removes all associated grants and tokens. Deleting a grant removes the grant record and all associated access tokens (found via the token:{userId}:{grantId}: prefix).
  10. Configure PKCE and Token Lifecycle

    main

    The provider manages the tokenEndpoint for exchanging authorization codes, refreshing tokens, and handling RFC 7009 revocation.

    PKCE Settings:

    • Public clients must use PKCE with authorization code flow. S256 is used by default.
    • allowPlainPKCE: Set to true to permit legacy clients that cannot use S256.

    Token Rotation:

    • Refresh tokens rotate on use. To prevent failures during network issues, the immediately previous token remains valid until its replacement is successfully used.
    allowPlainPKCE: true;
  11. Understand the OAUTH_KV storage schema

    main
    The OAuth 2.0 provider library uses Cloudflare Workers KV to store all OAuth-related data. The storage is organized into several types of objects identified by specific key prefixes. The system leverages KV's built-in TTL (Time-To-Live) functionality for automatic expiration of short-lived data like tokens and authorization codes. Additionally, the library implements end-to-end encryption for sensitive application-specific properties (props) to ensure that only holders of valid tokens can access this data.
  12. Implement the Authorization Flow with completeAuthorization()

    main

    The authorization endpoint is part of your defaultHandler. The provider is not an identity provider; you are responsible for authenticating the user and obtaining consent.

    1. Validate: Use env.OAUTH_PROVIDER.parseAuthRequest(request) to validate the client, redirect URI, response type, resource, and PKCE restrictions.
    2. Authenticate & Consent: Perform your application's user authentication and show a consent UI.
    3. Complete: Call env.OAUTH_PROVIDER.completeAuthorization(...). This method validates the response type again, writes the grant, and (by default) revokes existing grants for that user/client combination.

    Grant Management

    • Revocation: By default, completeAuthorization revokes existing grants for the same user and client. To allow concurrent grants, set revokeExistingGrants: false.
    • Batch Size: revokeExistingGrantsBatchSize controls the KV page size used when scanning for existing grants (defaults to 50, max 1000).

    Handling Errors and RFC 9207

    If you need to create a terminal OAuth error redirect, you should include the iss (issuer) parameter if available from parseAuthRequest() to comply with RFC 9207:

    const oauthRequest = await env.OAUTH_PROVIDER.parseAuthRequest(request);
    const redirect = new URL(oauthRequest.redirectUri);
    redirect.searchParams.set('error', 'access_denied');
    redirect.searchParams.set('state', oauthRequest.state);
    if (oauthRequest.issuer) redirect.searchParams.set('iss', oauthRequest.issuer);
    return Response.redirect(redirect.toString(), 302);