# MCP OAuth Inbound Policy

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.

```json title="config/policies.json"
{
  "name": "my-mcp-oauth-inbound-policy",
  "policyType": "mcp-oauth-inbound",
  "handler": {
    "export": "McpOAuthInboundPolicy",
    "module": "$import(@zuplo/runtime/mcp-gateway)",
    "options": {
      "oidc": {
        "issuer": "https://my-tenant.okta.com/",
        "jwksUrl": "https://my-tenant.okta.com/.well-known/jwks.json"
      },
      "browserLogin": {
        "url": "https://my-tenant.okta.com/oauth2/v1/authorize",
        "tokenUrl": "https://my-tenant.okta.com/oauth2/v1/token",
        "clientId": "$env(OIDC_CLIENT_ID)",
        "clientSecret": "$env(OIDC_CLIENT_SECRET)"
      }
    }
  }
}
```

### Policy Configuration

- `name` <code className="text-green-600">&lt;string&gt;</code> - The name of your policy instance. This is used as a reference in your routes.
- `policyType` <code className="text-green-600">&lt;string&gt;</code> - The identifier of the policy. This is used by the Zuplo UI. Value should be `mcp-oauth-inbound`.
- `handler.export` <code className="text-green-600">&lt;string&gt;</code> - The name of the exported type. Value should be `McpOAuthInboundPolicy`.
- `handler.module` <code className="text-green-600">&lt;string&gt;</code> - The module containing the policy. Value should be `$import(@zuplo/runtime/mcp-gateway)`.
- `handler.options` <code className="text-green-600">&lt;object&gt;</code> - The options for this policy. [See Policy Options](#policy-options) below.

### Policy Options

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

- `oidc` **(required)** <code className="text-green-600">&lt;object&gt;</code> - OpenID Connect identity provider that authenticates end-users before the gateway issues its own OAuth access token.
  - `issuer` **(required)** <code className="text-green-600">&lt;string&gt;</code> - The OIDC issuer URL of the identity provider.
  - `jwksUrl` **(required)** <code className="text-green-600">&lt;string&gt;</code> - The JWKS endpoint used to verify ID tokens issued by the identity provider.
  - `audience` <code className="text-green-600">&lt;string&gt;</code> - Optional IdP audience value. Leave unset when browser login ID tokens use the OIDC client_id as their audience.
- `browserLogin` **(required)** <code className="text-green-600">&lt;object&gt;</code> - Browser-side OAuth/OIDC settings used when the gateway redirects the user to the identity provider for login.
  - `url` **(required)** <code className="text-green-600">&lt;string&gt;</code> - The IdP /authorize endpoint to redirect the user to. For local development on loopback, use http://127.0.0.1:9000/oauth/dev-login.
  - `tokenUrl` <code className="text-green-600">&lt;string&gt;</code> - The IdP token endpoint used for the federated authorization code exchange. Required for federated_oidc browser login.
  - `clientId` <code className="text-green-600">&lt;string&gt;</code> - The OIDC client_id registered with the identity provider for the gateway's browser login flow.
  - `clientSecret` <code className="text-green-600">&lt;string&gt;</code> - The OIDC client_secret. Required for federated browser login. Use $env(...) to source from a secret environment variable.
  - `scope` <code className="text-green-600">&lt;string&gt;</code> - The OIDC scopes requested during browser login. Defaults to `"openid profile email"`.
  - `audience` <code className="text-green-600">&lt;string&gt;</code> - Optional audience parameter for the IdP authorization request (Auth0-style API audiences).
  - `remoteTimeoutMs` <code className="text-green-600">&lt;integer&gt;</code> - Timeout for outbound calls to the IdP (token exchange, JWKS fetch). Defaults to `10000`.
  - `stateTtlSeconds` <code className="text-green-600">&lt;integer&gt;</code> - Lifetime of an in-flight browser-login state record. Defaults to `900`.
  - `sessionTtlSeconds` <code className="text-green-600">&lt;integer&gt;</code> - Lifetime of the gateway browser-login session cookie issued after a successful login. Defaults to `28800`.
- `gateway` <code className="text-green-600">&lt;object&gt;</code> - Gateway-side OAuth token settings. The gateway issuer and advertised URLs are derived from the incoming request origin.
  - `accessTokenTtlSeconds` <code className="text-green-600">&lt;integer&gt;</code> - Lifetime of access tokens issued by /oauth/token. Defaults to `900`.
  - `refreshTokenTtlSeconds` <code className="text-green-600">&lt;integer&gt;</code> - Lifetime of refresh tokens issued by /oauth/token. Defaults to `2592000`.
  - `cimdEnabled` <code className="text-green-600">&lt;boolean&gt;</code> - Whether to advertise client_id_metadata_document_supported in AS metadata. Defaults to `true`.

## Using the Policy

# MCP OAuth Inbound

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.

## 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](/articles/policies)
