
# MCP Ping OAuth Policy

:::note{title="MCP Gateway Policy"}

This policy is for use with the [MCP Gateway](/mcp-gateway/introduction). 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,
with browser login delegated to PingOne.

This is a PingOne-friendly wrapper around `McpOAuthInboundPolicy`. Provide a
PingOne `environmentId`, or a PingOne `customDomain`, plus `clientId` and
`clientSecret`; the PingOne OIDC issuer, JWKS URL, and browser login endpoints
are derived automatically.

## Configuration

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

```json title="config/policies.json"
{
  "name": "my-mcp-ping-oauth-inbound-policy",
  "policyType": "mcp-ping-oauth-inbound",
  "handler": {
    "export": "McpPingOAuthInboundPolicy",
    "module": "$import(@zuplo/runtime)",
    "options": {
      "browserLoginOverrides": {
        "remoteTimeoutMs": 10000,
        "sessionTtlSeconds": 28800,
        "stateTtlSeconds": 900
      },
      "clientId": "$env(PING_CLIENT_ID)",
      "clientSecret": "$env(PING_CLIENT_SECRET)",
      "customDomain": "login.example.com",
      "environmentId": "11111111-1111-4111-8111-111111111111",
      "gateway": {
        "accessTokenTtlSeconds": 900,
        "cimdEnabled": true,
        "refreshTokenTtlSeconds": 2592000
      },
      "region": "north-america",
      "scope": "openid profile email"
    }
  }
}
```

### 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-ping-oauth-inbound`.
- `handler.export` <code className="text-green-600">&lt;string&gt;</code> - The name of the exported type. Value should be `McpPingOAuthInboundPolicy`.
- `handler.module` <code className="text-green-600">&lt;string&gt;</code> - The module containing the policy. Value should be `$import(@zuplo/runtime)`.
- `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.

- `environmentId` <code className="text-green-600">&lt;string&gt;</code> - The PingOne environment ID. Required unless customDomain is set.
- `region` <code className="text-green-600">&lt;string&gt;</code> - The PingOne geography for the environment. Ignored when customDomain is set. Allowed values are `north-america`, `canada`, `europe`, `singapore`, `australia`, `asia-pacific`. Defaults to `"north-america"`.
- `customDomain` <code className="text-green-600">&lt;string&gt;</code> - Optional PingOne custom domain, without https://, a trailing slash, or a path. When set, environmentId and region are not used.
- `clientId` **(required)** <code className="text-green-600">&lt;string&gt;</code> - The PingOne OIDC application client_id registered for the gateway's browser login flow.
- `clientSecret` **(required)** <code className="text-green-600">&lt;string&gt;</code> - The PingOne OIDC application client_secret. Use $env(...) to source from a secret environment variable.
- `scope` <code className="text-green-600">&lt;string&gt;</code> - OIDC scopes requested during browser login. Defaults to `"openid profile email"`.
- `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`.
- `browserLoginOverrides` <code className="text-green-600">&lt;object&gt;</code> - Optional overrides for the derived browser-login settings.
  - `remoteTimeoutMs` <code className="text-green-600">&lt;integer&gt;</code> - No description available. Defaults to `10000`.
  - `stateTtlSeconds` <code className="text-green-600">&lt;integer&gt;</code> - No description available. Defaults to `900`.
  - `sessionTtlSeconds` <code className="text-green-600">&lt;integer&gt;</code> - No description available. Defaults to `28800`.

## Using the Policy

# MCP Ping OAuth Inbound

Authenticate MCP gateway requests using a gateway-issued OAuth access token,
with browser login delegated to PingOne.

This is a thin PingOne-friendly wrapper around the generic
`McpOAuthInboundPolicy`. Use it when you want to configure browser login with a
PingOne environment ID and OAuth client credentials instead of the full set of
OIDC URLs.

## Derived configuration

For PingOne regional domains, provide `environmentId` and optional `region`. The
default region is `north-america`, which uses `auth.pingone.com`.

| Generic field                                      | Derived value                                           |
| -------------------------------------------------- | ------------------------------------------------------- |
| `oidc.issuer`                                      | `https://auth.pingone.com/{environmentId}/as`           |
| `oidc.jwksUrl`                                     | `https://auth.pingone.com/{environmentId}/as/jwks`      |
| `browserLogin.url`                                 | `https://auth.pingone.com/{environmentId}/as/authorize` |
| `browserLogin.tokenUrl`                            | `https://auth.pingone.com/{environmentId}/as/token`     |
| `browserLogin.clientId` / `clientSecret` / `scope` | from policy options (`clientSecret` is required)        |

Set `region` to one of `north-america`, `canada`, `europe`, `singapore`,
`australia`, or `asia-pacific` to use the corresponding PingOne auth domain.

If your PingOne environment uses a custom domain, set `customDomain` instead of
`environmentId` and `region`. The policy derives endpoints from
`https://{customDomain}/as`.

This policy is for PingOne cloud. PingFederate deployments can customize issuer
hosts, issuer paths, endpoint paths, and metadata templates; use
`McpOAuthInboundPolicy` for PingFederate.

## Configuration

```json
{
  "name": "ping-managed-oauth",
  "policyType": "mcp-ping-oauth-inbound",
  "handler": {
    "module": "$import(@zuplo/runtime)",
    "export": "McpPingOAuthInboundPolicy",
    "options": {
      "environmentId": "$env(PING_ENVIRONMENT_ID)",
      "region": "north-america",
      "clientId": "$env(PING_CLIENT_ID)",
      "clientSecret": "$env(PING_CLIENT_SECRET)"
    }
  }
}
```

For a custom domain:

```json
{
  "name": "ping-managed-oauth",
  "policyType": "mcp-ping-oauth-inbound",
  "handler": {
    "module": "$import(@zuplo/runtime)",
    "export": "McpPingOAuthInboundPolicy",
    "options": {
      "customDomain": "login.example.com",
      "clientId": "$env(PING_CLIENT_ID)",
      "clientSecret": "$env(PING_CLIENT_SECRET)"
    }
  }
}
```

`environmentId` must be a PingOne environment UUID, such as
`11111111-1111-4111-8111-111111111111`. Do not pass the PingOne issuer URL, auth
domain, or client ID in this field.

## Pairing

Pair this policy with `McpTokenExchangeInboundPolicy` and `McpProxyHandler`, the
same as `McpOAuthInboundPolicy`. Only one MCP OAuth policy is allowed per
project; attach the same policy by name to every MCP route.

Read more about [how policies work](/articles/policies)
