Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
154 changes: 141 additions & 13 deletions docs/toolhive/concepts/auth-framework.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -41,19 +41,40 @@ flexible, and auditable. You don't need to add custom authentication or
authorization logic to every server—ToolHive handles it for you, consistently
and securely.

## ToolHive vs. MCP specification
## Why ToolHive centralizes authentication

The
[official Model Context Protocol (MCP) specification](https://modelcontextprotocol.io/docs/tutorials/security/authorization)
recommends OAuth 2.1-based authorization for HTTP transports, which requires
each MCP server to act as an OAuth resource server that validates access tokens
and enforces scope-based access control. ToolHive takes a different approach: it
centralizes authentication and authorization in its proxy layer, using
OAuth/OIDC for authentication and Cedar for fine-grained authorization. This
means you don't need to implement token validation or scope management in every
server—just configure ToolHive with your IdP and write clear Cedar policies.
This approach is more flexible, secure, and easier to manage for you and your
team.
[official MCP specification](https://modelcontextprotocol.io/docs/tutorials/security/authorization)
recommends OAuth 2.1-based authorization for HTTP transports, where each MCP
server acts as an OAuth resource server. In practice, this model creates
significant operational challenges:

- **OAuth client registration burden:** OAuth 2.0 requires pre-registered
redirect URIs at each identity provider. Many providers—such as Google,
GitHub, and Atlassian—require manual registration of OAuth clients to obtain a
client ID and client secret. If each user client (for example, an IDE) were
its own OAuth client, the registration burden would be impractical at scale.
- **No federation with external services:** While token exchange (RFC 8693) and
federated identity providers work when the upstream service is in the same
trust domain as the MCP server or has an established trust relationship with
the identity provider, many MCP servers need to access external services like
GitHub, Google, or Atlassian APIs where no federation relationship exists.
- **Per-server implementation cost:** Each MCP server would need to implement
its own token validation and scope management, duplicating security-critical
logic across servers.

ToolHive addresses these challenges by centralizing authentication and
authorization in its proxy layer. You configure ToolHive with your identity
provider and write Cedar policies for fine-grained authorization—individual MCP
servers don't need to implement token validation or scope management.

With the [embedded authorization server](#embedded-authorization-server),
ToolHive can also manage interactive token acquisition. The proxy exposes
standard OAuth endpoints and handles the full OAuth web flow—clients don't need
to obtain or manage tokens externally. ToolHive delegates authentication to an
upstream identity provider and issues its own tokens, giving MCP clients a
spec-compliant OAuth experience while centralizing the complexity of client
registration and token management.

## Authentication framework

Expand Down Expand Up @@ -146,6 +167,110 @@ flowchart TD
Cedar_Authorizer -->|Deny| Denied[403 Forbidden]
```

### Embedded authorization server

In the standard authentication flow described above, clients obtain tokens
independently from an external identity provider and present them to ToolHive
for validation. The embedded authorization server provides an alternative model
where ToolHive itself acts as an OAuth authorization server, retrieving tokens
from an upstream identity provider on behalf of clients.

:::note

The embedded authorization server is currently available only for Kubernetes
deployments using the ToolHive Operator.

:::

This approach is designed for MCP servers that accept `Authorization: Bearer`
tokens and is particularly useful when you want ToolHive to handle the full
OAuth flow rather than requiring clients to obtain tokens independently.

#### How the embedded authorization server works

The embedded authorization server runs in-process within the ToolHive proxy.
When a client connects, the following flow occurs:

1. If the client is not yet registered, it registers via Dynamic Client
Registration (DCR), receiving a `client_id` and `client_secret`.
2. The client is directed to the ToolHive authorization endpoint.
3. The proxy redirects the client to the upstream identity provider for
authentication.
4. The user authenticates with the upstream identity provider (for example,
signing in with Google or GitHub).
5. The upstream identity provider redirects back to the proxy with an
authorization code.
6. The embedded authorization server exchanges the authorization code for tokens
with the upstream identity provider.
7. The embedded authorization server issues its own JWT to the client, signed
with keys you configure.
8. The client includes this JWT as a `Bearer` token in the `Authorization`
header on subsequent requests.
9. The proxy validates the JWT, retrieves the upstream token, and forwards
requests to the MCP server.

```mermaid
sequenceDiagram
participant Client
participant Proxy as ToolHive Proxy
participant IdP as Upstream IdP
participant MCP as MCP Server

Client->>Proxy: POST /oauth/register (DCR)
Proxy-->>Client: client_id + client_secret
Client->>Proxy: Connect to MCP server
Proxy-->>Client: Redirect to /oauth/authorize
Client->>Proxy: GET /oauth/authorize
Proxy-->>Client: Redirect to upstream IdP
Client->>IdP: Authenticate
IdP-->>Client: Redirect with authorization code
Client->>Proxy: GET /oauth/callback?code=...
Proxy->>IdP: Exchange code for tokens
IdP-->>Proxy: Upstream tokens
Proxy-->>Client: Issue ToolHive JWT
Client->>Proxy: MCP request with Bearer token
Proxy->>Proxy: Validate JWT
Proxy->>MCP: Forward request
MCP-->>Proxy: Response
Proxy-->>Client: Response
```

#### Key characteristics

- **In-process execution:** The authorization server runs within the ToolHive
proxy—no separate infrastructure or sidecar containers needed.
- **Configurable signing keys:** JWTs are signed with keys you provide,
supporting key rotation for zero-downtime updates.
- **Flexible upstream providers:** Supports both OIDC providers (with automatic
endpoint discovery) and OAuth 2.0 providers (with explicit endpoint
configuration).
- **Configurable token lifespans:** Access tokens, refresh tokens, and
authorization codes have configurable durations with sensible defaults.
- **Dynamic Client Registration (DCR):** Supports OAuth 2.0 Dynamic Client
Registration (RFC 7591), allowing MCP clients to register automatically
without manual configuration at the identity provider.
- **Direct upstream redirect:** The embedded authorization server redirects
clients directly to the upstream provider for authentication (for example,
GitHub or Atlassian).
- **Single upstream provider:** Currently supports one upstream identity
provider per configuration.

:::info[Chained authentication not yet supported]

The embedded authorization server redirects clients directly to the upstream
provider. This means the upstream provider must be the service whose API the MCP
server calls. Chained authentication—where a client authenticates with a
corporate IdP like Okta, which then federates to an external provider like
GitHub—is not yet supported. If your deployment requires this pattern, consider
using [token exchange](./backend-auth.mdx#same-idp-with-token-exchange) with a
federated identity provider instead.

:::

For guidance on choosing the right backend authentication pattern for your MCP
servers, see
[Choosing the right backend authentication model](./backend-auth.mdx#choosing-the-right-backend-authentication-model).

### Identity providers

ToolHive can integrate with any provider that supports OAuth 2.1 or OIDC,
Expand All @@ -158,8 +283,9 @@ including:
- Auth0
- Kubernetes (service account tokens)

This flexibility lets you use your existing identity infrastructure for both
users and services, reducing operational overhead and improving security.
These same providers work with both external token validation and the embedded
authorization server. For the embedded authorization server, the upstream
provider must support the OAuth 2.0 authorization code flow.

### Token validation methods

Expand Down Expand Up @@ -280,6 +406,8 @@ standardized across clients.

## Related information

- For configuring the embedded authorization server in Kubernetes, see
[Embedded authorization server authentication](../guides-k8s/auth-k8s.mdx#set-up-embedded-authorization-server-authentication)
- For backend authentication concepts, see
[Backend authentication](./backend-auth.mdx)
- For detailed policy writing guidance, see
Expand Down
25 changes: 25 additions & 0 deletions docs/toolhive/concepts/backend-auth.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -283,8 +283,33 @@ ToolHive's token exchange approach provides several key advantages:
- **Consistent:** The same pattern works across different backend services and
identity providers

## Choosing the right backend authentication model

How you configure backend authentication depends on what the MCP server needs to
call and how that backend service accepts credentials:

- **Static credentials or API keys:** If the MCP server only supports static
credentials or API keys, configure them in ToolHive directly—either as
environment variables, secrets, or injected headers. No token exchange or
embedded authorization server is needed.
- **Token exchange:** If the MCP server makes authenticated API calls to a
backend service in the same trust domain as your corporate identity provider
(for example, an internal API that accepts tokens from your Okta or Entra ID
tenant), or federation exists between the two, token exchange is a good fit.
ToolHive exchanges the client's token for a backend-scoped token using RFC
8693, preserving the user's identity across services.
- **Embedded authorization server:** If the MCP server needs to call an external
API where no federation relationship exists—such as GitHub, Google, or
Atlassian APIs—the
[embedded authorization server](./auth-framework.mdx#embedded-authorization-server)
is a good fit. It runs the full OAuth web flow against the external provider,
obtaining tokens that the MCP server can use to access those APIs on behalf of
the user.

## Related information

- For client authentication concepts, see
[Authentication and authorization](./auth-framework.mdx)
- For the embedded authorization server, see
[Embedded authorization server](./auth-framework.mdx#embedded-authorization-server)
- For policy configuration, see [Cedar policies](./cedar-policies.mdx)
Loading