> ## Documentation Index
> Fetch the complete documentation index at: https://portkey-docs-chore-gateway-2-19-0.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# OAuth Client Metadata

> Customize OAuth client metadata for MCP servers.

When Portkey connects to OAuth-protected MCP servers using **OAuth Auto**, it registers as an OAuth client with the server's authorization endpoint. By default, Portkey uses standard client metadata. For compliance or branding requirements, you can customize this.

## When to Use

Customize OAuth client metadata when:

* The OAuth server requires a pre-registered `software_id` or specific scopes
* You need custom branding during OAuth consent screens (your company name/logo instead of Portkey's)
* Compliance requires specific contact info, terms of service, or privacy policy URLs
* The MCP server expects specific OAuth client configuration

***

## How It Works

When a user first accesses an OAuth-protected MCP server, Portkey initiates the OAuth flow. As part of this process, Portkey presents client metadata to the authorization server (per RFC 7591 - OAuth 2.0 Dynamic Client Registration).

```
1. User requests tool from MCP server
2. Portkey initiates OAuth flow with authorization server
3. Authorization server shows consent screen with client metadata
4. User sees your company name/logo instead of default Portkey branding
5. User authorizes access
6. Flow completes normally
```

***

## Configuration

When setting up your MCP integration in the MCP Registry, expand **Advanced Settings** and paste your client metadata into the **OAuth Metadata** field as a plain JSON object:

```json theme={null}
{
  "client_name": "Your Company Name",
  "client_uri": "https://yourcompany.com",
  "logo_uri": "https://yourcompany.com/logo.png",
  "software_id": "com.yourcompany.mcp-gateway",
  "scope": "mcp:servers:read mcp:tools:execute",
  "contacts": ["support@yourcompany.com"],
  "tos_uri": "https://yourcompany.com/terms",
  "policy_uri": "https://yourcompany.com/privacy"
}
```

<Warning>
  Do **not** wrap this in an outer `oauth_metadata` key when using the **OAuth Metadata** field. The field's contents are stored as your OAuth metadata directly, so an extra wrapper nests your settings one level too deep and Portkey ignores them silently — including a `client_id`, which causes Portkey to fall back to Dynamic Client Registration.

  The wrapper is only correct in the separate **Advanced Configuration** JSON box, which merges its top-level keys into the integration's configuration:

  ```json theme={null}
  {
    "oauth_metadata": {
      "client_name": "Your Company Name",
      "client_uri": "https://yourcompany.com",
      "logo_uri": "https://yourcompany.com/logo.png",
      "software_id": "com.yourcompany.mcp-gateway",
      "scope": "mcp:servers:read mcp:tools:execute",
      "contacts": ["support@yourcompany.com"],
      "tos_uri": "https://yourcompany.com/terms",
      "policy_uri": "https://yourcompany.com/privacy"
    }
  }
  ```
</Warning>

All the examples on this page show the contents of the **OAuth Metadata** field. If you use the **Advanced Configuration** box instead, nest each one under `oauth_metadata`.

***

## Available Fields

| Field                        | Type      | Description                                                                                           |
| ---------------------------- | --------- | ----------------------------------------------------------------------------------------------------- |
| `client_id`                  | string    | Pre-registered OAuth client ID. Setting this disables Dynamic Client Registration for the integration |
| `client_secret`              | string    | Pre-registered OAuth client secret, for confidential clients                                          |
| `client_name`                | string    | Name shown during OAuth consent                                                                       |
| `client_uri`                 | string    | Organization's homepage URL                                                                           |
| `logo_uri`                   | string    | Logo shown during consent (should be HTTPS)                                                           |
| `scope`                      | string    | Space-separated OAuth scopes to request                                                               |
| `software_id`                | string    | Unique client identifier (useful for pre-registered clients)                                          |
| `software_version`           | string    | Client software version                                                                               |
| `grant_types`                | string\[] | OAuth grant types (default: `["authorization_code", "refresh_token"]`)                                |
| `response_types`             | string\[] | OAuth response types (default: `["code"]`)                                                            |
| `token_endpoint_auth_method` | string    | Token endpoint auth method (default: `"none"`)                                                        |
| `contacts`                   | string\[] | Contact email addresses                                                                               |
| `tos_uri`                    | string    | Terms of Service URL                                                                                  |
| `policy_uri`                 | string    | Privacy policy URL                                                                                    |
| `authorization_params`       | object    | Extra query parameters appended to the upstream authorization URL (string values only)                |

***

## Default Values

If not customized, Portkey uses:

| Field                        | Default Value                             |
| ---------------------------- | ----------------------------------------- |
| `client_name`                | `"Portkey (workspaceId/serverId)"`        |
| `client_uri`                 | `"https://portkey.ai"`                    |
| `logo_uri`                   | Portkey logo                              |
| `software_id`                | `"ai.portkey.mcp"`                        |
| `grant_types`                | `["authorization_code", "refresh_token"]` |
| `response_types`             | `["code"]`                                |
| `token_endpoint_auth_method` | `"none"`                                  |

***

## Security Notes

### redirect\_uris Cannot Be Customized

The `redirect_uris` field is **never customizable**. Portkey always uses its own callback URL for OAuth flows:

```
<gateway-url>/oauth/upstream-callback
```

This ensures OAuth tokens are delivered securely to Portkey's gateway, not to an arbitrary URL.

### Fields That Cannot Be Set

The following fields are excluded from customization:

* `redirect_uris` - Must be gateway-controlled for security
* `jwks_uri` - Not yet supported
* `jwks` - Not yet supported
* `software_statement` - Not yet supported

If you include these fields, they're ignored.

### Authorization Parameters That Cannot Be Set

`authorization_params` cannot override the parameters Portkey and the MCP SDK own, because doing so would break PKCE or the callback correlation:

`response_type`, `client_id`, `client_secret`, `code_challenge`, `code_challenge_method`, `redirect_uri`, `state`, `scope`, `resource`

Any of these keys in `authorization_params` are ignored and logged as a warning. Use the `scope` field of `oauth_metadata` to change requested scopes.

***

## Example: Enterprise Compliance

Your enterprise requires all OAuth registrations to include legal contact information and link to corporate policies:

```json theme={null}
{
  "client_name": "Acme Corp MCP Gateway",
  "client_uri": "https://acme.com",
  "logo_uri": "https://acme.com/assets/logo.png",
  "software_id": "com.acme.mcp-gateway",
  "software_version": "1.0.0",
  "scope": "mcp:read mcp:write",
  "contacts": ["security@acme.com", "legal@acme.com"],
  "tos_uri": "https://acme.com/legal/terms",
  "policy_uri": "https://acme.com/legal/privacy"
}
```

When users authorize access, they see "Acme Corp MCP Gateway" with your logo instead of generic Portkey branding.

***

## Example: Pre-Registered Client

Some OAuth servers require clients to be pre-registered with a specific `software_id`:

```json theme={null}
{
  "software_id": "registered-client-12345",
  "client_name": "Pre-Registered MCP Client"
}
```

***

## Example: Custom Scopes

Request specific OAuth scopes from the MCP server:

```json theme={null}
{
  "scope": "read:projects write:issues admin:webhooks"
}
```

The authorization server will request consent for these specific scopes.

***

## Example: Servers Without Dynamic Client Registration (GitHub)

Some MCP servers like GitHub don't support OAuth Dynamic Client Registration (DCR). For these servers, create an OAuth App manually and provide the credentials to Portkey.

**Required fields for non-DCR servers:**

| Field                        | Description                                                                                                                                                                        |
| ---------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `client_id`                  | OAuth App client ID from the service                                                                                                                                               |
| `client_secret`              | OAuth App client secret from the service (only for confidential apps)                                                                                                              |
| `scope`                      | Scopes to request during authorization                                                                                                                                             |
| `token_endpoint_auth_method` | Set to `client_secret_post` or `client_secret_basic` if the OAuth App is registered as a confidential/web client. The default is `none`, which such apps reject at token exchange. |

Providing a `client_id` disables Dynamic Client Registration entirely for that integration — Portkey presents the client you configured instead of trying to register a new one.

**GitHub example:**

```json theme={null}
{
  "client_id": "Iv1.a1b2c3d4e5f6g7h8",
  "client_secret": "your_github_oauth_client_secret",
  "scope": "repo read:org"
}
```

<Note>
  Set the OAuth App's **Authorization callback URL** to Portkey's callback, `<gateway-url>/oauth/upstream-callback`. On Portkey's managed gateway that is `https://mcp.portkey.ai/oauth/upstream-callback`; on a self-hosted or hybrid deployment, use your own gateway host (the value of `MCP_GATEWAY_BASE_URL`). This URL is always controlled by the gateway, so a `redirect_uri` set in your OAuth metadata is ignored.
</Note>

See the [GitHub MCP server guide](/integrations/mcp-servers/github-mcp-server#connect-via-portkey-mcp-gateway) for complete setup instructions.

***

## Example: Provider-Specific Authorization Parameters (Google)

Some providers require query parameters on the authorization request that the OAuth spec doesn't define. Google is the common case: it only returns a **refresh token** when the authorization request carries `access_type=offline`, and only re-issues one for a user who has already consented when `prompt=consent` is also present.

Without a refresh token, Portkey has nothing to renew the connection with, so the user is pushed back through consent once the access token expires (one hour for Google).

Add these with `authorization_params`:

```json theme={null}
{
  "oauth_metadata": {
    "client_id": "...apps.googleusercontent.com",
    "client_secret": "your_google_oauth_client_secret",
    "redirect_uri": "https://mcp.portkey.ai/oauth/upstream-callback",
    "scope": "https://www.googleapis.com/auth/drive.readonly",
    "authorization_params": {
      "access_type": "offline",
      "prompt": "consent"
    }
  }
}
```

Portkey appends every key in `authorization_params` to the upstream authorization URL on each auth flow. Values must be strings; non-string values are ignored.

<Note>
  Connections authorized **before** this setting was added have no stored refresh token, and Google skips consent for a user who has already granted access — so the setting alone won't fix them. Remove the affected user's connection and have them authorize again; `prompt=consent` guarantees a refresh token on that pass.
</Note>

For external authorization providers, set `authorization_params` inside `external_auth_config` instead.

## Troubleshooting

**Portkey still attempts Dynamic Client Registration even though I set a `client_id`.**
Portkey resolved no client ID from your configuration, so it fell back to registration. Check that the JSON in the **OAuth Metadata** field has `client_id` at the top level, with no outer `oauth_metadata` wrapper. If you configured it through the **Advanced Configuration** box instead, the wrapper is required there — but it must appear exactly once.

**Consent succeeds, then the token exchange fails.**
The client ID is being presented correctly and the failure is now on the provider side. In order of likelihood: the OAuth App is registered as a confidential/web client while Portkey defaults to `token_endpoint_auth_method: "none"` (set it explicitly, and supply `client_secret`); the callback URL registered on the provider doesn't exactly match `<gateway-url>/oauth/upstream-callback`; or the app is missing a granted scope or the `refresh_token` grant, which Portkey requests by default.

***

## Related

| Topic                                                             | Description                             |
| ----------------------------------------------------------------- | --------------------------------------- |
| [Authentication Overview](/product/mcp-gateway/authentication)    | How authentication layers work          |
| [External MCP Servers](/product/mcp-gateway/external-mcp-servers) | Adding OAuth-protected external servers |

***

<Card title="Portkey is now PRISMA AIRS AI Gateway. See it in action." href="https://www.paloaltonetworks.in/ai-security/ai-gateway?utm_source=portkey&utm_medium=referral&utm_campaign=prisma_airs&utm_content=docs_nav#contact" icon="arrow-up-right-from-square">
  Contact Us
</Card>
