> ## Documentation Index
> Fetch the complete documentation index at: https://docs.portkey.ai/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Bring Your Own Auth

> Use your own identity provider for gateway authentication.

External OAuth enables using your existing identity provider (Okta, Auth0, Azure AD, Descope, Cognito) instead of Portkey's built-in authentication. Users authenticate with corporate credentials—no Portkey accounts needed.

## When to Use

Organizations with existing IdPs can use External OAuth. Users authenticate through the IdP for other services, and MCP access works the same way.

Common scenarios:

* **SSO for internal developers.** Engineers use corporate credentials to access MCP servers
* **B2B applications.** Your customers authenticate through their own IdP
* **Compliance requirements.** Mandate use of your own identity infrastructure
* **No Portkey accounts.** Users who aren't in Portkey need MCP access

***

## How It Works

```
1. The request authenticates to the Portkey gateway
   (Portkey API key, or a JWT carrying Portkey org claims)
2. User authenticates with your IdP and obtains a token (JWT or opaque)
3. User includes that token in the MCP request to Portkey
4. Portkey validates the token against your IdP (JWKS or introspection)
5. Request proceeds with the user identity attached
```

Step 1 establishes your organization context; the `jwt_validation` in step 4 is a per-server check layered on top of it. Portkey never handles user credentials—your IdP remains the source of truth for identity.

***

## Configuration

Configure JWT validation for your MCP server. Portkey validates incoming tokens using your IdP's public keys or introspection endpoint.

### Option 1: JWKS URI (Recommended)

The most common setup. Portkey fetches public keys from your IdP's JWKS endpoint.

```json theme={"system"}
{
  "jwt_validation": {
    "jwksUri": "https://your-idp.com/.well-known/jwks.json",
    "algorithms": ["RS256"],
    "requiredClaims": ["sub", "email"]
  }
}
```

**How it works:**

* Portkey fetches and caches your IdP's public keys
* Keys are cached for 24 hours by default
* If a key rotates, Portkey automatically refetches
* Validation happens locally (no network call per request)

### Option 2: Token Introspection

For opaque tokens requiring real-time validation, or for immediate revocation.

```json theme={"system"}
{
  "jwt_validation": {
    "introspectEndpoint": "https://your-idp.com/oauth/introspect",
    "introspectContentType": "application/x-www-form-urlencoded",
    "introspectClientId": "<client-id>",
    "introspectClientSecret": "<client-secret>",
    "headerKey": "X-Auth-Token",
    "introspectCacheMaxAge": 0
  }
}
```

**How it works:**

* The request authenticates to the gateway first (Portkey API key or org-claim JWT); introspection runs **after** that step.
* Portkey reads the end-user's opaque token from the header named by `headerKey` (default: `Authorization`). Use a dedicated header such as `X-Auth-Token` so it doesn't collide with the gateway credential.
* Portkey POSTs to your `introspectEndpoint` per [RFC 7662](https://datatracker.ietf.org/doc/html/rfc7662): the token in the request body as `token=…`, and—when `introspectClientId`/`introspectClientSecret` are set—an `Authorization: Basic base64(client_id:client_secret)` header to identify Portkey to your endpoint.
* Your endpoint must return `{ "active": true, ... }`. Include a `sub` claim so the user is attributed correctly in logs and analytics.
* Responses are cached for `introspectCacheMaxAge` seconds (default: `0`, no caching).

**Caching tradeoff:**

* `0` (no cache): Every request calls the introspection endpoint (slower, but immediate revocation)
* `> 0`: Better performance, but revocation takes up to the cache TTL to take effect

<Note>
  Token introspection validates the **end-user's** token; it does **not** authenticate the gateway. You still need a Portkey API key or an org-claim JWT on the request (see the callout at the top of this page). An opaque token on its own is not sufficient.
</Note>

See [JWT Validation](/product/mcp-gateway/authentication/jwt) for full configuration options.

***

## Client Configuration

Every request needs a **gateway credential** (a Portkey API key or an org-claim JWT) so Portkey can resolve your organization. When you use token introspection, the **end-user token** goes in a separate header—the one you set as `headerKey`:

```json theme={"system"}
{
  "mcpServers": {
    "linear": {
      "url": "https://mcp.portkey.ai/linear/mcp",
      "headers": {
        "x-portkey-api-key": "YOUR_PORTKEY_API_KEY",
        "X-Auth-Token": "opaque-or-idp-token..."
      }
    }
  }
}
```

If your IdP issues **JWTs that already carry Portkey org claims** (`portkey_oid` / `organisation_id`, `portkey_workspace` / `workspace_slug`), you can pass that JWT in `x-portkey-api-key` and it serves as the gateway credential on its own—see [Organization JWT Authentication](/product/enterprise-offering/org-management/jwt). In that case no separate Portkey API key is required.

Or in code:

<Tabs>
  <Tab title="Python">
    ```python theme={"system"}
    # Get the end-user token from your IdP (example using OIDC)
    token = get_idp_token()  # Your IdP client

    headers = {
        "x-portkey-api-key": "YOUR_PORTKEY_API_KEY",  # gateway credential
        "X-Auth-Token": token,                         # end-user token (introspected)
    }

    async with streamablehttp_client(
        "https://mcp.portkey.ai/linear/mcp",
        headers=headers
    ) as (read, write, _):
        # MCP operations...
    ```
  </Tab>

  <Tab title="TypeScript">
    ```typescript theme={"system"}
    // Get the end-user token from your IdP
    const token = await getIdpToken();  // Your IdP client

    const client = new MCPClient({
      url: "https://mcp.portkey.ai/linear/mcp",
      headers: {
        "x-portkey-api-key": "YOUR_PORTKEY_API_KEY",  // gateway credential
        "X-Auth-Token": token,                         // end-user token (introspected)
      },
    });
    ```
  </Tab>
</Tabs>

***

## Validating Claim Values

Validate that tokens are issued by the correct IdP and intended for MCP access:

```json theme={"system"}
{
  "jwt_validation": {
    "jwksUri": "https://your-idp.com/.well-known/jwks.json",
    "algorithms": ["RS256"],
    "requiredClaims": ["sub", "email"],
    "claimValues": {
      "iss": {
        "values": "https://your-idp.com",
        "matchType": "exact"
      },
      "aud": {
        "values": ["api://mcp", "https://mcp.yourcompany.com"],
        "matchType": "contains"
      }
    }
  }
}
```

This prevents:

* Tokens from other IdPs being accepted
* Tokens intended for other services being used for MCP

***

## Combining with Identity Forwarding

External OAuth pairs naturally with identity forwarding. Portkey validates the incoming JWT, extracts user claims, and forwards them to MCP servers.

```json theme={"system"}
{
  "jwt_validation": {
    "jwksUri": "https://your-idp.com/.well-known/jwks.json",
    "requiredClaims": ["sub", "email", "groups"]
  },
  "user_identity_forwarding": {
    "method": "claims_header",
    "include_claims": ["sub", "email", "groups"]
  }
}
```

The MCP server receives user identity without handling OAuth itself. It can use this for:

* **Authorization**: Check if user belongs to required groups
* **Logging**: Audit trail with user identity
* **Personalization**: Customize responses based on user

See [Identity Forwarding](/product/mcp-gateway/authentication/identity-forwarding).

***

## IdP-Specific Examples

### Descope

1. Create a project in the [Descope Console](https://app.descope.com)
2. Note your Project ID (found in **[Project Settings](https://app.descope.com/settings/project)**)
3. Enable DCR, under DCR Settings under Inbound Applications

```json theme={"system"}
{
  "jwt_validation": {
    "jwksUri": "https://api.descope.com/{project-id}/.well-known/jwks.json",
    "algorithms": ["RS256"],
    "claimValues": {
      "iss": {
        "values": "https://api.descope.com/v1/apps/{project-id}",
        "matchType": "exact"
      }
    }
  }
}
```

### Okta

1. Create an authorization server in Okta Admin Console
2. Create an OAuth application (Web or SPA)
3. Note your issuer URL (e.g., `https://dev-12345.okta.com/oauth2/default`)

```json theme={"system"}
{
  "jwt_validation": {
    "jwksUri": "https://dev-12345.okta.com/oauth2/default/v1/keys",
    "algorithms": ["RS256"],
    "claimValues": {
      "iss": {
        "values": "https://dev-12345.okta.com/oauth2/default",
        "matchType": "exact"
      }
    }
  }
}
```

### Auth0

1. Create an API in Auth0 Dashboard
2. Note your tenant domain and API identifier

```json theme={"system"}
{
  "jwt_validation": {
    "jwksUri": "https://your-tenant.auth0.com/.well-known/jwks.json",
    "algorithms": ["RS256"],
    "claimValues": {
      "iss": {
        "values": "https://your-tenant.auth0.com/",
        "matchType": "exact"
      },
      "aud": {
        "values": "https://your-api-identifier",
        "matchType": "exact"
      }
    }
  }
}
```

### Azure AD / Entra ID

1. Register an application in Azure Portal
2. Note your tenant ID and client ID

```json theme={"system"}
{
  "jwt_validation": {
    "jwksUri": "https://login.microsoftonline.com/{tenant-id}/discovery/v2.0/keys",
    "algorithms": ["RS256"],
    "claimValues": {
      "iss": {
        "values": "https://login.microsoftonline.com/{tenant-id}/v2.0",
        "matchType": "exact"
      },
      "aud": {
        "values": "{client-id}",
        "matchType": "exact"
      }
    }
  }
}
```

### AWS Cognito

1. Create a User Pool in AWS Console
2. Note your region and pool ID

```json theme={"system"}
{
  "jwt_validation": {
    "jwksUri": "https://cognito-idp.{region}.amazonaws.com/{pool-id}/.well-known/jwks.json",
    "algorithms": ["RS256"],
    "claimValues": {
      "iss": {
        "values": "https://cognito-idp.{region}.amazonaws.com/{pool-id}",
        "matchType": "exact"
      }
    }
  }
}
```

***

## Securing Your Setup

### Validate Issuer and Audience

Always configure `claimValues` to verify `iss` and `aud`:

```json theme={"system"}
{
  "claimValues": {
    "iss": {
      "values": "https://your-idp.com",
      "matchType": "exact"
    },
    "aud": {
      "values": "your-client-id-or-api-identifier",
      "matchType": "exact"
    }
  }
}
```

Without this, tokens intended for other applications might be accepted.

### Require Essential Claims

Require essential claims:

```json theme={"system"}
{
  "requiredClaims": ["sub", "email"]
}
```

If a claim is missing, the request is rejected.

### Use Short Token Lifetimes

Configure the IdP to issue short-lived access tokens (15-60 minutes). This limits the window if a token is compromised.

***

## Troubleshooting

### 401 Unauthorized when sending only an end-user token

If you send only an opaque (or IdP) token with no Portkey API key and no org-claim JWT, the gateway can't resolve your organization, so it rejects the request *before* introspection runs (your introspection endpoint is never called, and the client may fall into a browser OAuth prompt). Add a gateway credential—`x-portkey-api-key` or an org-claim JWT—and pass the end-user token in the `headerKey` header.

### "Invalid issuer" Error

The token's `iss` claim doesn't match your configuration. Verify the issuer URL exactly matches—including trailing slashes.

### "Missing required claims" Error

The token doesn't include claims you specified in `requiredClaims`. Check your IdP's token configuration and scopes.

### "Invalid audience" Error

The token's `aud` claim doesn't match your configuration. Verify the correct API identifier or client ID.

### "JWKS fetch failed" Error

Portkey couldn't fetch keys from your JWKS URI. Verify the URL is accessible and returns valid JWKS JSON.

***

## Related

| Topic                                                                          | Description                                     |
| ------------------------------------------------------------------------------ | ----------------------------------------------- |
| [JWT Validation](/product/mcp-gateway/authentication/jwt)                      | Full configuration reference for JWT validation |
| [Identity Forwarding](/product/mcp-gateway/authentication/identity-forwarding) | Pass validated claims to MCP servers            |
| [Authentication Overview](/product/mcp-gateway/authentication)                 | Understanding gateway authentication            |
