From 9fbce993abab5f7e44e673e020f96d04712ee8ca Mon Sep 17 00:00:00 2001 From: Jakub Hrozek Date: Mon, 16 Feb 2026 09:56:15 +0000 Subject: [PATCH 1/2] Restructure backend auth docs for balanced pattern coverage The backend-auth.mdx page was heavily weighted toward token exchange while the embedded authorization server and static credentials got minimal coverage. Restructure so all three backend auth patterns get equal treatment with their own sections, diagrams, and guidance. Maintain the page separation: auth-framework.mdx focuses on client-to-MCP-server authentication, backend-auth.mdx focuses on MCP-server-to-backend authentication. The embedded authorization server spans both concerns, so each page covers its respective perspective. Key changes to backend-auth.mdx: - Add static credentials section with Vault cross-reference - Add embedded authorization server section with OAuth flow diagram, key characteristics, and tsid-based token storage/forwarding detail - Reorganize token exchange content under "Token exchange in depth" - Replace verbose choosing-the-right-model bullets with decision table - Broaden front matter, intro, and benefits to cover all patterns Key changes to auth-framework.mdx: - Trim embedded auth server section to focus on client-facing flow - Add cross-reference to backend-auth.mdx for backend token details - Fix "Why ToolHive centralizes" to attribute per-server cost to centralization and registration/federation gaps to the auth server --- docs/toolhive/concepts/auth-framework.mdx | 121 +++-------- docs/toolhive/concepts/backend-auth.mdx | 254 +++++++++++++++++----- 2 files changed, 227 insertions(+), 148 deletions(-) diff --git a/docs/toolhive/concepts/auth-framework.mdx b/docs/toolhive/concepts/auth-framework.mdx index 63ed4e1d..e033580d 100644 --- a/docs/toolhive/concepts/auth-framework.mdx +++ b/docs/toolhive/concepts/auth-framework.mdx @@ -63,18 +63,20 @@ significant operational challenges: 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. +ToolHive addresses the per-server implementation cost 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. + +The [embedded authorization server](#embedded-authorization-server) addresses +the remaining challenges. It exposes standard OAuth endpoints and handles the +full OAuth web flow, eliminating the client registration burden through Dynamic +Client Registration (DCR) and solving the federation gap by obtaining tokens +directly from external providers like GitHub or Atlassian. ToolHive delegates +authentication to the upstream provider and issues its own tokens, giving MCP +clients a spec-compliant OAuth experience while centralizing the complexity of +token acquisition and management. ## Authentication framework @@ -182,94 +184,27 @@ 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: +From the client's perspective, the embedded authorization server provides a +standard OAuth 2.0 experience: 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` +3. ToolHive redirects the client to the upstream identity provider for + authentication (for example, signing in with GitHub or Atlassian). +4. ToolHive exchanges the authorization code for upstream tokens and issues its + own JWT to the client, signed with keys you configure. +5. 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. - -::: +Behind the scenes, ToolHive stores the upstream tokens and uses them to +authenticate MCP server requests to external APIs. For the complete flow +including how upstream tokens are stored and delivered to MCP servers, see +[Embedded authorization server](./backend-auth.mdx#embedded-authorization-server) +in the backend authentication documentation. -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). +For Kubernetes setup instructions, see +[Set up embedded authorization server authentication](../guides-k8s/auth-k8s.mdx#set-up-embedded-authorization-server-authentication). ### Identity providers diff --git a/docs/toolhive/concepts/backend-auth.mdx b/docs/toolhive/concepts/backend-auth.mdx index 359f31c3..550257d5 100644 --- a/docs/toolhive/concepts/backend-auth.mdx +++ b/docs/toolhive/concepts/backend-auth.mdx @@ -2,13 +2,14 @@ title: Backend authentication description: Understanding how MCP servers authenticate to external services using - ToolHive's token exchange framework. + ToolHive's backend authentication patterns, including token exchange, + federated identity, and the embedded authorization server. --- This document explains how ToolHive helps MCP servers authenticate to third-party APIs and backend services exposed through the MCP servers. You'll -learn about the backend authentication patterns ToolHive supports, why its -approach improves security and multi-tenancy, and how it simplifies MCP server +learn about the backend authentication patterns ToolHive supports, why they +improve security and multi-tenancy, and how they simplify MCP server development. :::info[Scope of this documentation] @@ -40,40 +41,52 @@ authentication code. This creates several problems: - **Multi-tenancy complexity:** Supporting multiple tenants with isolated credentials requires significant custom code -ToolHive addresses these challenges by implementing several authentication -patterns such as token exchange and federated identity that provide MCP servers -with properly scoped, short-lived access tokens instead of requiring embedded -secrets. +ToolHive addresses these challenges with three backend authentication patterns: +static credentials for services that don't support OAuth, token exchange for +services in the same or federated trust domain, and the embedded authorization +server for OAuth-based external APIs where no federation exists. -## Managing third-party service tokens +## How ToolHive handles backend authentication -The key insight is that ToolHive already implements authentication and -authorization for the MCP server—it helps the client authenticate and obtain an -access token scoped for the MCP server. ToolHive can leverage this existing -token to obtain a token for the backend service and pass it to the MCP server. +ToolHive sits between clients and MCP servers, and can acquire backend +credentials on behalf of the MCP server. Depending on the pattern, it might +exchange the client's token, run an OAuth flow against an external provider, or +inject static credentials. In each case, the MCP server receives ready-to-use +credentials—typically in the `Authorization: Bearer` header—without needing to +implement custom authentication logic or manage secrets directly. -This means the MCP server receives a properly scoped token for the external -service as part of the standard MCP protocol call, typically in the -`Authorization: Bearer` header. This simplifies MCP server implementation -because: +## Backend authentication patterns -- No long-lived tokens need to be stored -- No custom authentication code is required -- The MCP server can focus on its business logic -- Each request is attributed to the individual user making it +ToolHive supports three patterns for backend authentication. Which one you use +depends on the relationship between your identity provider (IdP) and the backend +service. -## Methods for acquiring external access tokens +### Static credentials and API keys -ToolHive supports multiple patterns for obtaining external access tokens, -depending on the relationship between your identity provider (IdP) and the -external service. All patterns assume OAuth-based authentication. For services -using other authentication methods (such as database connections with static -credentials), consider integrations with secret management systems like -[HashiCorp Vault](../tutorials/vault-integration.mdx). +When a backend service requires API keys, database passwords, or other static +credentials, you can configure them directly in ToolHive as environment +variables, secret files, or injected headers. -ToolHive implements two main patterns: +This is the simplest pattern, but it provides the least security and +auditability. Static credentials are long-lived and shared across all users, so +there is no per-user attribution in audit logs. -### Same IdP with token exchange +When using static credentials, consider integrating with a secret management +system like [HashiCorp Vault](../tutorials/vault-integration.mdx) for secure +storage and rotation. + +### Token exchange + +When the backend service trusts the same IdP as your MCP clients—or federation +is configured between the two IdPs—ToolHive can exchange the client's token for +one scoped to the backend service using +[RFC 8693](https://datatracker.ietf.org/doc/html/rfc8693) token exchange. This +preserves the user's identity across services and provides short-lived, narrowly +scoped tokens. Because the trust relationship between services is pre-configured +at the IdP, no consent screen or user interaction is required—the exchange is +transparent to the end user. + +#### Same IdP with token exchange When both the MCP server and the backend service trust the same IdP, and that IdP supports [RFC 8693](https://datatracker.ietf.org/doc/html/rfc8693) token @@ -106,7 +119,7 @@ flowchart LR 4. ToolHive passes this access token to the MCP server 5. The MCP server uses the access token to call the upstream service -### Federated IdPs with identity mapping +#### Federated IdPs with identity mapping When the backend service trusts a different IdP, but federation is configured between the two IdPs, ToolHive can use the federated identity service to issue @@ -140,7 +153,149 @@ flowchart LR 4. ToolHive passes token_B to the MCP server 5. The MCP server uses token_B to call the upstream service -## Token exchange implementation +### Embedded authorization server + +When the MCP server needs to call an external API where no federation +relationship exists—such as GitHub, Google Workspace, or Atlassian APIs—the +embedded authorization server handles the full OAuth web flow against the +external provider. The proxy redirects the user to authenticate directly with +the external service, obtains tokens on behalf of the user, and passes the +upstream token to the MCP server. + +```mermaid +flowchart LR + User[User] + Proxy[ToolHive Proxy] + ExtProvider[External Provider] + + User -->|connect| Proxy + Proxy -->|redirect to login| ExtProvider + User -->|authenticate| ExtProvider + ExtProvider -->|authorization code| Proxy + Proxy -->|exchange code for token| ExtProvider + Proxy -->|issue JWT| User +``` + +**How it works:** + +1. The client connects to ToolHive +2. ToolHive redirects the user to the external provider (for example, GitHub) + for authentication +3. The user authenticates with the external provider +4. ToolHive receives an authorization code and exchanges it for upstream tokens +5. ToolHive stores the upstream tokens and issues its own JWT to the client + +On subsequent MCP requests, ToolHive uses the JWT to retrieve the stored +upstream tokens and forward them to the MCP server. For details on this +mechanism, see [Token storage and forwarding](#token-storage-and-forwarding). + +The embedded authorization server runs in-process within the ToolHive proxy—no +separate infrastructure is needed. It supports Dynamic Client Registration +(DCR), so MCP clients can register automatically without manual configuration at +the external provider. + +:::note + +The embedded authorization server is currently available only for Kubernetes +deployments using the ToolHive Operator. + +::: + +#### 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](#same-idp-with-token-exchange) with a federated identity +provider instead. + +::: + +#### Token storage and forwarding + +The embedded authorization server stores upstream tokens (access tokens, refresh +tokens, and ID tokens from external providers) in session storage. When the +OAuth flow completes, the server generates a unique session ID and stores the +upstream tokens keyed by this ID. The JWT issued to the client contains a `tsid` +(Token Session ID) claim that references this session. + +When a client makes an MCP request with this JWT: + +1. The ToolHive proxy validates the JWT signature and extracts the `tsid` claim +2. It retrieves the upstream tokens from session storage using the `tsid` +3. The proxy replaces the `Authorization` header with the upstream access token +4. The request is forwarded to the MCP server with the external provider's token + +```mermaid +sequenceDiagram + participant Client + participant Proxy as ToolHive Proxy + participant Store as Session Storage + participant MCP as MCP Server + participant API as External API + + Note over Client,Store: Initial OAuth flow + Proxy->>Store: Store upstream tokens
keyed by session ID + Proxy-->>Client: Issue JWT with tsid claim + + Note over Client,API: Subsequent MCP requests + Client->>Proxy: MCP request with JWT + Proxy->>Proxy: Validate JWT signature + Proxy->>Store: Look up upstream token
using tsid from JWT + Store-->>Proxy: Return upstream access token + Proxy->>MCP: Forward request with
upstream access token + MCP->>API: Call external API + API-->>MCP: Response + MCP-->>Proxy: Response + Proxy-->>Client: Response +``` + +This mechanism allows MCP servers to call external APIs with the user's actual +credentials from the upstream provider, while the client only needs to manage a +single ToolHive-issued JWT. + +:::warning[Session storage limitations] + +In Kubernetes deployments, session storage is currently in-memory only. Upstream +tokens are lost when pods restart, requiring users to re-authenticate. + +::: + +For the client-facing OAuth flow, see +[Embedded authorization server](./auth-framework.mdx#embedded-authorization-server). +For Kubernetes setup instructions, see +[Set up embedded authorization server authentication](../guides-k8s/auth-k8s.mdx#set-up-embedded-authorization-server-authentication). + +## Token exchange in depth + +This section provides implementation details for the token exchange patterns +described above. For setup instructions, see +[Configure token exchange](../guides-cli/token-exchange.mdx) (CLI) or +[Configure token exchange in Kubernetes](../guides-k8s/token-exchange-k8s.mdx). + +### Token exchange implementation The token exchange flow demonstrates how ToolHive transforms user identity tokens into properly scoped service tokens. @@ -195,14 +350,12 @@ Notice how the audience (`aud`) and scopes (`scp`) change while preserving the user's identity (`sub`). This exchanged token is then injected into the `Authorization: Bearer` HTTP header and passed to the MCP server. -## Token exchange with federation +### Federation flow When using federated identity providers, ToolHive can map your corporate identity to an external service identity. This is particularly useful for accessing cloud services like Google Cloud Platform. -### Federation flow - The client authenticates with your corporate IdP and receives a token: ```json @@ -268,7 +421,7 @@ Federation-based token exchange has several important characteristics: ## Security and operational benefits -ToolHive's token exchange approach provides several key advantages: +ToolHive's backend authentication patterns provide several key advantages: - **Secure:** MCP servers receive short-lived, properly scoped access tokens instead of embedding long-lived secrets @@ -285,26 +438,12 @@ ToolHive's token exchange approach provides several key advantages: ## 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. +| Scenario | Pattern | Why | +| ------------------------------------------------------------------- | -------------------------------------------------------------------- | ----------------------------------------------------------------- | +| Backend only accepts API keys or static credentials | [Static credentials](#static-credentials-and-api-keys) | No OAuth support; configure credentials directly in ToolHive | +| Backend trusts the same IdP as your clients | [Token exchange (same IdP)](#same-idp-with-token-exchange) | Exchange the client token for a backend-scoped token via RFC 8693 | +| Backend trusts a federated IdP (for example, Google Cloud) | [Token exchange (federation)](#federated-idps-with-identity-mapping) | Map your corporate identity to the federated service | +| Backend is an external API with no federation (for example, GitHub) | [Embedded authorization server](#embedded-authorization-server) | Run the full OAuth flow against the external provider | ## Related information @@ -312,4 +451,9 @@ call and how that backend service accepts credentials: [Authentication and authorization](./auth-framework.mdx) - For the embedded authorization server, see [Embedded authorization server](./auth-framework.mdx#embedded-authorization-server) +- For configuring the embedded authorization server in Kubernetes, see + [Set up embedded authorization server authentication](../guides-k8s/auth-k8s.mdx#set-up-embedded-authorization-server-authentication) +- For configuring token exchange, see + [Configure token exchange](../guides-cli/token-exchange.mdx) (CLI) or + [Configure token exchange in Kubernetes](../guides-k8s/token-exchange-k8s.mdx) - For policy configuration, see [Cedar policies](./cedar-policies.mdx) From 43ef10d97bed2048af22acef6c1dba66e725ecaa Mon Sep 17 00:00:00 2001 From: Jakub Hrozek Date: Wed, 18 Feb 2026 10:54:04 +0000 Subject: [PATCH 2/2] Fix inaccurate wording in backend auth docs Address PR review feedback: - Add static credentials to frontmatter description - Clarify credential delivery covers headers and env vars - Scope DCR descriptions to ToolHive registration --- docs/toolhive/concepts/backend-auth.mdx | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/docs/toolhive/concepts/backend-auth.mdx b/docs/toolhive/concepts/backend-auth.mdx index 550257d5..ff808f81 100644 --- a/docs/toolhive/concepts/backend-auth.mdx +++ b/docs/toolhive/concepts/backend-auth.mdx @@ -2,8 +2,8 @@ title: Backend authentication description: Understanding how MCP servers authenticate to external services using - ToolHive's backend authentication patterns, including token exchange, - federated identity, and the embedded authorization server. + ToolHive's backend authentication patterns, including static credentials, + token exchange, and the embedded authorization server. --- This document explains how ToolHive helps MCP servers authenticate to @@ -52,8 +52,9 @@ ToolHive sits between clients and MCP servers, and can acquire backend credentials on behalf of the MCP server. Depending on the pattern, it might exchange the client's token, run an OAuth flow against an external provider, or inject static credentials. In each case, the MCP server receives ready-to-use -credentials—typically in the `Authorization: Bearer` header—without needing to -implement custom authentication logic or manage secrets directly. +credentials—via an `Authorization: Bearer` header, another header, or +environment variables, depending on the pattern—without needing to implement +custom authentication logic or manage secrets directly. ## Backend authentication patterns @@ -191,8 +192,8 @@ mechanism, see [Token storage and forwarding](#token-storage-and-forwarding). The embedded authorization server runs in-process within the ToolHive proxy—no separate infrastructure is needed. It supports Dynamic Client Registration -(DCR), so MCP clients can register automatically without manual configuration at -the external provider. +(DCR), so MCP clients can register automatically with ToolHive—no manual client +configuration in ToolHive is required. :::note @@ -213,8 +214,9 @@ deployments using the ToolHive Operator. - **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. + Registration (RFC 7591), allowing MCP clients to register automatically with + ToolHive's authorization server—no manual client registration in ToolHive is + required. - **Direct upstream redirect:** The embedded authorization server redirects clients directly to the upstream provider for authentication (for example, GitHub or Atlassian).