ZuploZuplo
LoginStart for Free
  • Documentation
  • API Reference
Getting Started
Concepts
API Management
AI Gateway
MCP Gateway
    Overview
    Getting Started
      How it works
      Connect MCP clients
      Authentication
      Cross App Access
      Configuration
      Policies
        Overview
        Authorization
          Generic OAuthAuth0 OAuthClerk OAuthAmazon Cognito OAuthMicrosoft Entra OAuthGoogle OAuthKeycloak OAuthLogto OAuthOkta OAuthOneLogin OAuthPingOne OAuthWorkOS OAuthToken Exchange
        Security & Validation
      Observability
      ReferenceServer RegistryTroubleshooting
    MCP Server
    Developer Portal
    Development
    Deploying & Source Control
    Analytics
    Observability
    Networking & Infrastructure
    Account Management
    Programming API
    Build with AI
    Zuplo CLI
    Migration Guides
    Platform LimitsVersion Support PolicySecuritySupportTrust & ComplianceChangelog
    powered by Zuplo
    Authorization

    MCP OAuth Policy

    MCP Gateway Policy

    This policy is for use with the MCP Gateway. See the MCP Gateway documentation to learn how to proxy and secure MCP servers with Zuplo.

    Authenticate MCP gateway requests using a gateway-issued OAuth access token.

    This policy hosts the gateway's OAuth authorization server endpoints (DCR, /authorize, /token, /callback) and validates the bearer token presented by the MCP client on protected MCP routes keyed by operationId. Browser login is delegated to a generic OpenID Connect identity provider configured via browserLogin and oidc policy options.

    Pair this policy with McpTokenExchangeInboundPolicy and McpProxyHandler to expose a protected transparent MCP upstream. For provider-friendly configuration, use McpAuth0OAuthInboundPolicy instead.

    Configuration

    The configuration shows how to configure the policy in the 'policies.json' document.

    Code
    { "name": "my-mcp-oauth-inbound-policy", "policyType": "mcp-oauth-inbound", "handler": { "export": "McpOAuthInboundPolicy", "module": "$import(@zuplo/runtime)", "options": { "browserLogin": { "clientSecret": "$env(MCP_OAUTH_CLIENT_SECRET)", "pkce": "none", "remoteTimeoutMs": 10000, "scope": "openid profile email", "sessionTtlSeconds": 28800, "stateTtlSeconds": 900, "tokenUrl": "https://my-tenant.us.auth0.com/oauth/token", "url": "https://my-tenant.us.auth0.com/authorize" }, "gateway": { "accessTokenTtlSeconds": 900, "cimdEnabled": true, "refreshTokenTtlSeconds": 2592000 }, "oidc": { "audience": "https://gateway.example.com", "issuer": "https://my-tenant.us.auth0.com/", "jwksUrl": "https://my-tenant.us.auth0.com/.well-known/jwks.json" } } } }

    Policy Configuration

    • name <string> - The name of your policy instance. This is used as a reference in your routes.
    • policyType <string> - The identifier of the policy. This is used by the Zuplo UI. Value should be mcp-oauth-inbound.
    • handler.export <string> - The name of the exported type. Value should be McpOAuthInboundPolicy.
    • handler.module <string> - The module containing the policy. Value should be $import(@zuplo/runtime).
    • handler.options <object> - The options for this policy. See Policy Options below.

    Policy Options

    The options for this policy are specified below. All properties are optional unless specifically marked as required.

    • oidc (required) <object> - OpenID Connect identity provider that authenticates end-users before the gateway issues its own OAuth access token.
      • issuer (required) <string> - The OIDC issuer URL of the identity provider.
      • jwksUrl (required) <string> - The JWKS endpoint used to verify ID tokens issued by the identity provider.
      • audience <string> - Optional IdP audience value. Leave unset when browser login ID tokens use the OIDC client_id as their audience.
    • browserLogin (required) <object> - Browser-side OAuth/OIDC settings used when the gateway redirects the user to the identity provider for login.
      • url (required) <string> - The IdP /authorize endpoint to redirect the user to. For local development on loopback, use http://127.0.0.1:9000/\_\_zuplo/oauth/dev-login (the gateway's default basePath is /__zuplo; adjust if the plugin is configured with a different one).
      • tokenUrl <string> - The IdP token endpoint used for the federated authorization code exchange. Required for federated_oidc browser login.
      • clientId <string> - The OIDC client_id registered with the identity provider for the gateway's browser login flow.
      • clientSecret <string> - The OIDC client_secret. Required for federated browser login. Use $env(...) to source from a secret environment variable.
      • scope <string> - The OIDC scopes requested during browser login. Defaults to "openid profile email".
      • audience <string> - Optional audience parameter for the IdP authorization request (Auth0-style API audiences).
      • pkce <string> - Whether to send S256 PKCE on the federated browser-login authorization request and replay the verifier at the token exchange. Defaults to "none". Set to "S256" when the identity provider mandates PKCE on the authorization-code flow (e.g. OAuth 2.1 IdPs, hardened Okta/Entra tenants). Leave as "none" for IdPs that may reject unexpected PKCE parameters. Allowed values are S256, none. Defaults to "none".
      • remoteTimeoutMs <integer> - Timeout for outbound calls to the IdP (token exchange, JWKS fetch). Defaults to 10000.
      • stateTtlSeconds <integer> - Lifetime of an in-flight browser-login state record. Defaults to 900.
      • sessionTtlSeconds <integer> - Lifetime of the gateway browser-login session cookie issued after a successful login. Defaults to 28800.
    • gateway <object> - Gateway-side OAuth token settings. The gateway issuer and advertised URLs are derived from the incoming request origin.
      • accessTokenTtlSeconds <integer> - Lifetime of access tokens issued by /oauth/token. Defaults to 900.
      • refreshTokenTtlSeconds <integer> - Lifetime of refresh tokens issued by /oauth/token. Defaults to 2592000.
      • cimdEnabled <boolean> - Whether to advertise client_id_metadata_document_supported in AS metadata. Defaults to true.
    • idJag <undefined> - Optional Identity Assertion JWT Authorization Grant (ID-JAG / XAA) support for the gateway token endpoint.

    Using the Policy

    Authenticate MCP gateway requests using a gateway-issued OAuth access token.

    How it works

    This policy is the inbound side of Zuplo's MCP gateway:

    1. When the gateway boots and sees this policy in policies.json, it registers the OAuth flow endpoints (/oauth/register, /oauth/authorize, /oauth/token, /oauth/callback, etc.) on this gateway.
    2. The MCP client connects, gets back a WWW-Authenticate challenge, and walks the OAuth flow. Browser login is delegated to the OpenID Connect identity provider configured under oidc + browserLogin options.
    3. After login, the gateway issues its own OAuth access token. The client presents that token on subsequent MCP route requests keyed by operationId.
    4. This policy validates the bearer token, strips the downstream bearer header, and exposes the authenticated gateway identity on request.user for downstream policies and handlers.

    Pairing with token exchange

    Pair this policy with McpTokenExchangeInboundPolicy (which resolves upstream credentials per the user) and a terminal MCP handler. Routes use McpProxyHandler to handle MCP transport method probes and forward native MCP POST requests to the upstream URL configured on the handler.

    ChatGPT connector setup

    When creating a ChatGPT connector for a Zuplo-hosted MCP gateway, choose Dynamic Client Registration (DCR) in ChatGPT's advanced OAuth settings. The gateway exposes /oauth/register, and DCR lets ChatGPT create a dedicated OAuth client for the connector instance without requiring the gateway runtime to fetch ChatGPT-hosted client metadata.

    Avoid selecting Client Identifier Metadata Document (CIMD) for ChatGPT connectors unless the gateway can fetch both of these URLs from its production runtime:

    • https://chatgpt.com/oauth/{connector_id}/client.json
    • https://chatgpt.com/oauth/jwks.json

    CIMD uses the metadata document URL as the OAuth client_id. The authorization server must fetch that document during authorization and, for ChatGPT's private_key_jwt flow, fetch the JWKS during token exchange. If those fetches are blocked by an upstream edge challenge, the user will see a generic invalid_client or "OAuth client is not registered" failure even though the gateway's DCR endpoint is configured correctly.

    Recommended ChatGPT advanced OAuth settings:

    SettingValue
    Registration methodDynamic Client Registration (DCR)
    Default scopesmcp:tools, or the action-level scopes required by tools
    Base scopesOnly scopes that must be requested on every auth request

    Keep the discovered Registration URL set to this gateway's /oauth/register endpoint. ChatGPT supports both CIMD and DCR, but DCR is the reliable registration path for ChatGPT connectors using this policy. See the OpenAI Apps SDK authentication docs and the MCPJam OAuth conformance docs for the registration methods and conformance test flow.

    Provider-specific wrappers

    For Auth0-friendly configuration (just auth0Domain instead of all OIDC URLs), use McpAuth0OAuthInboundPolicy. The wrapper is a thin shim around this generic policy.

    Read more about how policies work

    Edit this page
    Last modified on September 25, 2026
    OverviewAuth0 OAuth
    On this page
    • Configuration
      • Policy Configuration
      • Policy Options
    • Using the Policy
    • How it works
    • Pairing with token exchange
    • ChatGPT connector setup
    • Provider-specific wrappers
    JSON