# OAuth & MCP Credentials

The Agent Gateway sits between your agents and downstream MCP servers or LLM providers. When those downstream services require authentication, the Gateway needs to know how to supply credentials on behalf of the caller. Three modes cover the full range of deployment patterns.

| Mode                  | Who holds the credential | Per-user isolation | Best for                                                  |
| --------------------- | ------------------------ | ------------------ | --------------------------------------------------------- |
| **Internal**          | Gateway (shared)         | No                 | Public APIs, internal tools with no per-user auth         |
| **OAuth Passthrough** | Client                   | Yes                | Third-party SaaS where users already have accounts        |
| **Token Broker**      | Admin API                | Yes                | Multi-tenant platforms with centrally managed credentials |

***

### Internal (Static Token)

The simplest mode. The Gateway uses a single shared connection to the downstream server. All users share the same downstream credentials, if any are required.

**How it works:**

1. Client authenticates with the Gateway using an API key or JWT.
2. The Gateway creates one shared connection to the downstream MCP server.
3. That connection is cached and reused across all requests to this server.

**Configuration:**

```yaml
mcpServers:
  internal-search:
    url: http://internal-search.company.internal
    description: Internal search service
    auth_mode: internal
```

**Use when:** The downstream service is a public API, an unauthenticated internal tool, or a shared service credential is acceptable across all users.

***

### OAuth Passthrough

The client obtains an OAuth token directly from the upstream provider and passes it to the Gateway. The Gateway forwards it unchanged to the downstream server. This mode keeps credentials out of the Gateway entirely — it never stores or exchanges them.

**How it works:**

1. Client sends `Authorization: Bearer <upstream-token>` to the Gateway.
2. The Gateway optionally validates a separate Highflame API key for Shield policy enforcement.
3. The upstream Bearer token is forwarded as-is to the downstream MCP server.
4. A fresh server connection is created per request (not cached).

**OAuth discovery flow** (for MCP clients that don't yet have a token):

1. Client sends a request with no auth → Gateway returns `401` with `WWW-Authenticate: Bearer resource_metadata="/.well-known/oauth-protected-resource"`.
2. Client fetches `GET /mcp/{slug}/.well-known/oauth-protected-resource` → Gateway proxies the upstream provider's OAuth metadata, rewriting the `resource` field to point to the Gateway.
3. Client completes the OAuth 2.1 + PKCE flow directly with the upstream provider (GitHub, Slack, Linear, etc.).
4. Client returns with the upstream token and the request proceeds.

**Configuration:**

```yaml
mcpServers:
  github:
    url: https://api.github.com
    description: GitHub MCP server
    auth_mode: oauth_passthrough
```

**Use when:** Users already have accounts with the downstream service (GitHub, Slack, Linear, Cloudflare, etc.) and should authenticate directly with it. The Gateway acts as a secure proxy without ever seeing or storing the credential.

***

### Token Broker

The Gateway fetches a user-specific downstream token from the Admin API on behalf of each caller. This mode lets your platform centrally manage downstream credentials without distributing them to clients.

**How it works:**

1. Client authenticates with the Gateway using a JWT (obtained from Highflame's OAuth flow).
2. The Gateway extracts the `user_id` from the JWT's `sub` claim.
3. The Gateway calls the Admin API: `GET /api/v1/downstream-tokens/{server_slug}` scoped to the account, project, and user.
4. The Admin API returns the user's encrypted downstream token.
5. The Gateway injects it as `Authorization: Bearer <downstream-token>` in the request to the downstream server.
6. The token is cached in-memory for 5 minutes per (user, server) pair.
7. A fresh server connection is created per request.

**Configuration:**

```yaml
mcpServers:
  salesforce:
    url: https://salesforce-mcp.company.com
    description: Salesforce MCP server
    auth_mode: token_broker
```

The Admin API URL must be configured via `HIGHFLAME_ADMIN_URL`.

**Use when:** You are building a multi-tenant SaaS platform where each user has distinct credentials for a third-party service, and those credentials are managed centrally (stored in your backend and served to the Gateway via the Admin API).

***

### Authentication at the Gateway

Regardless of which credential mode the downstream server uses, clients authenticate with the Gateway itself using one of the following methods, resolved in priority order:

| Priority | Method                 | Header                            |
| -------- | ---------------------- | --------------------------------- |
| 1        | Highflame API key      | `X-Highflame-APIKey: hf_sk_...`   |
| 2        | Service key as Bearer  | `Authorization: Bearer hf_sk_...` |
| 3        | RS256 JWT (OAuth)      | `Authorization: Bearer eyJ...`    |
| 4        | Legacy Bearer fallback | `Authorization: Bearer <other>`   |

JWT tokens are validated against the Highflame JWKS endpoint. The signing keys are refreshed every 5 minutes in the background, with a lazy refresh triggered if an unknown key ID is encountered.

***

### Shield Integration

When Shield is enabled, all requests are evaluated through the guardrail pipeline before being forwarded to the downstream server, regardless of credential mode. The Gateway sends the request content, tool context, and MCP metadata to Shield. If Shield returns `deny`, the request is blocked with a `403`. Shield failures (network errors, timeouts) are fail-open by default — the request proceeds with a warning logged.

See [Shield Integration](/agent-identity-zeroid/guides/shield-integration.md) for policy configuration.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.highflame.ai/agent-gateway/credential-modes.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
