Skip to content

Commit dca8035

Browse files
committed
Extract embedded auth server concept page
1 parent e3889e6 commit dca8035

7 files changed

Lines changed: 238 additions & 167 deletions

File tree

docs/toolhive/concepts/auth-framework.mdx

Lines changed: 13 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -174,33 +174,19 @@ flowchart TD
174174
In the standard authentication flow described above, clients obtain tokens
175175
independently from an external identity provider and present them to ToolHive
176176
for validation. The embedded authorization server provides an alternative model
177-
where ToolHive itself acts as an OAuth authorization server, retrieving tokens
178-
from an upstream identity provider on behalf of clients.
179-
180-
:::note
181-
182-
The embedded authorization server is currently available only for Kubernetes
183-
deployments using the ToolHive Operator.
184-
185-
:::
186-
187-
From the client's perspective, the embedded authorization server provides a
188-
standard OAuth 2.0 experience:
189-
190-
1. If the client is not yet registered, it registers via Dynamic Client
191-
Registration (DCR), receiving a `client_id` and `client_secret`.
192-
2. The client is directed to the ToolHive authorization endpoint.
193-
3. ToolHive redirects the client to the upstream identity provider for
194-
authentication (for example, signing in with GitHub or Atlassian).
195-
4. ToolHive exchanges the authorization code for upstream tokens and issues its
196-
own JWT to the client, signed with keys you configure.
197-
5. The client includes this JWT as a `Bearer` token in the `Authorization`
198-
header on subsequent requests.
199-
200-
Behind the scenes, ToolHive stores the upstream tokens and uses them to
201-
authenticate MCP server requests to external APIs. For the complete flow,
202-
including token storage and forwarding, see
203-
[Embedded authorization server](./backend-auth.mdx#embedded-authorization-server).
177+
where ToolHive itself acts as an OAuth authorization server, obtaining tokens
178+
from an upstream provider on behalf of clients—then storing those tokens and
179+
issuing its own JWTs for clients to use on subsequent requests.
180+
181+
This solves two problems at once: it eliminates the client registration burden
182+
through Dynamic Client Registration (DCR), and it bridges the gap for external
183+
APIs like GitHub or Atlassian where no federation relationship exists with your
184+
identity provider.
185+
186+
For the complete conceptual description—including the OAuth flow, token storage
187+
and forwarding, session storage options, and differences between MCPServer and
188+
VirtualMCPServer—see
189+
[Embedded authorization server](./embedded-auth-server.mdx).
204190

205191
For Kubernetes setup instructions, see
206192
[Set up embedded authorization server authentication](../guides-k8s/auth-k8s.mdx#set-up-embedded-authorization-server-authentication).

docs/toolhive/concepts/backend-auth.mdx

Lines changed: 9 additions & 120 deletions
Original file line numberDiff line numberDiff line change
@@ -159,137 +159,26 @@ When the MCP server needs to call an external API where no federation
159159
relationship exists—such as GitHub, Google Workspace, or Atlassian APIs—the
160160
embedded authorization server handles the full OAuth web flow against the
161161
external provider. The proxy redirects the user to authenticate directly with
162-
the external service, obtains tokens on behalf of the user, and passes the
163-
upstream token to the MCP server.
164-
165-
```mermaid
166-
sequenceDiagram
167-
participant User
168-
participant Proxy as ToolHive Proxy
169-
participant ExtProvider as External Provider
170-
171-
User->>Proxy: Connect
172-
Proxy-->>User: Redirect to login
173-
User->>ExtProvider: Authenticate
174-
ExtProvider->>Proxy: Authorization code
175-
Proxy->>ExtProvider: Exchange code for token
176-
ExtProvider->>Proxy: Upstream tokens
177-
Proxy->>User: Issue JWT
178-
```
179-
180-
On subsequent MCP requests, ToolHive uses the JWT to retrieve the stored
181-
upstream tokens and forward them to the MCP server. For details on this
182-
mechanism, see [Token storage and forwarding](#token-storage-and-forwarding).
162+
the external service, obtains tokens on behalf of the user, and automatically
163+
forwards the upstream token to the MCP server on each subsequent request.
183164

184165
The embedded authorization server runs in-process within the ToolHive proxy—no
185166
separate infrastructure is needed. It supports Dynamic Client Registration
186167
(DCR), so MCP clients can register automatically with ToolHive—no manual client
187168
configuration in ToolHive is required.
188169

170+
For a full explanation of how the OAuth flow works, token storage and
171+
forwarding, automatic token refresh, session storage options, and differences
172+
between MCPServer and VirtualMCPServer deployments, see
173+
[Embedded authorization server](./embedded-auth-server.mdx).
174+
189175
:::note
190176

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

194180
:::
195181

196-
#### Key characteristics
197-
198-
- **In-process execution:** The authorization server runs within the ToolHive
199-
proxy—no separate infrastructure or sidecar containers needed.
200-
- **Configurable signing keys:** JWTs are signed with keys you provide,
201-
supporting key rotation for zero-downtime updates.
202-
- **Flexible upstream providers:** Supports both OIDC providers (with automatic
203-
endpoint discovery) and OAuth 2.0 providers (with explicit endpoint
204-
configuration).
205-
- **Configurable token lifespans:** Access tokens, refresh tokens, and
206-
authorization codes have configurable durations with sensible defaults.
207-
- **Dynamic Client Registration (DCR):** Supports OAuth 2.0 Dynamic Client
208-
Registration (RFC 7591), allowing MCP clients to register automatically with
209-
ToolHive's authorization server—no manual client registration in ToolHive is
210-
required.
211-
- **Direct upstream redirect:** The embedded authorization server redirects
212-
clients directly to the upstream provider for authentication (for example,
213-
GitHub or Atlassian).
214-
- **Single upstream provider per MCPServer:** Individual MCPServer resources
215-
support one upstream identity provider per configuration. For multiple
216-
upstream providers with sequential authorization chaining, use a
217-
[VirtualMCPServer with the embedded auth server](../guides-vmcp/authentication.mdx#embedded-authorization-server).
218-
219-
#### Token storage and forwarding
220-
221-
The embedded authorization server stores upstream tokens (access tokens, refresh
222-
tokens, and ID tokens from external providers) in session storage. When the
223-
OAuth flow completes, the server generates a unique session ID and stores the
224-
upstream tokens keyed by this ID. The JWT issued to the client contains a `tsid`
225-
(Token Session ID) claim that references this session.
226-
227-
When a client makes an MCP request with this JWT:
228-
229-
1. The ToolHive proxy validates the JWT signature and extracts the `tsid` claim
230-
2. It retrieves the upstream tokens from session storage using the `tsid`
231-
3. The proxy replaces the `Authorization` header with the upstream access token
232-
4. The request is forwarded to the MCP server with the external provider's token
233-
234-
```mermaid
235-
sequenceDiagram
236-
participant Client
237-
participant Proxy as ToolHive Proxy
238-
participant Store as Session Storage
239-
participant MCP as MCP Server
240-
participant API as External API
241-
242-
Note over Client,Store: Initial OAuth flow
243-
Proxy->>Store: Store upstream tokens<br/>keyed by session ID
244-
Proxy-->>Client: Issue JWT with tsid claim
245-
246-
Note over Client,API: Subsequent MCP requests
247-
Client->>Proxy: MCP request with JWT
248-
Proxy->>Proxy: Validate JWT signature
249-
Proxy->>Store: Look up upstream token<br/>using tsid from JWT
250-
Store-->>Proxy: Return upstream access token
251-
Proxy->>MCP: Forward request with<br/>upstream access token
252-
MCP->>API: Call external API
253-
API-->>MCP: Response
254-
MCP-->>Proxy: Response
255-
Proxy-->>Client: Response
256-
```
257-
258-
This mechanism allows MCP servers to call external APIs with the user's actual
259-
credentials from the upstream provider, while the client only needs to manage a
260-
single ToolHive-issued JWT.
261-
262-
#### Automatic token refresh
263-
264-
Upstream access tokens have their own expiration, independent of the ToolHive
265-
JWT lifespan. When the stored upstream access token has expired, ToolHive
266-
automatically refreshes it using the stored refresh token before forwarding the
267-
request — your MCP session continues without re-authentication.
268-
269-
If the refresh token is also expired or has been revoked by the upstream
270-
provider, ToolHive returns a `401` response, prompting you to re-authenticate
271-
through the OAuth flow.
272-
273-
:::warning[Session storage limitations]
274-
275-
By default, session storage is in-memory only. Upstream tokens are lost when
276-
pods restart, requiring users to re-authenticate. For production deployments,
277-
configure Redis Sentinel as the storage backend for persistent, highly available
278-
session storage. See
279-
[Configure session storage](../guides-k8s/auth-k8s.mdx#configure-session-storage)
280-
for a quick setup, or the full
281-
[Redis Sentinel session storage](../guides-k8s/redis-session-storage.mdx)
282-
tutorial for an end-to-end walkthrough.
283-
284-
:::
285-
286-
For the client-facing OAuth flow, see
287-
[Embedded authorization server](./auth-framework.mdx#embedded-authorization-server).
288-
For Kubernetes setup instructions, see
289-
[Set up embedded authorization server authentication](../guides-k8s/auth-k8s.mdx#set-up-embedded-authorization-server-authentication).
290-
For multi-upstream provider support with vMCP, see
291-
[vMCP embedded authorization server](../guides-vmcp/authentication.mdx#embedded-authorization-server).
292-
293182
## Token exchange in depth
294183

295184
This section provides implementation details for the token exchange patterns
@@ -459,8 +348,8 @@ setup guide.
459348

460349
- For client authentication concepts, see
461350
[Authentication and authorization](./auth-framework.mdx)
462-
- For the embedded authorization server, see
463-
[Embedded authorization server](./auth-framework.mdx#embedded-authorization-server)
351+
- For a deep dive into the embedded authorization server, see
352+
[Embedded authorization server](./embedded-auth-server.mdx)
464353
- For configuring the embedded authorization server in Kubernetes, see
465354
[Set up embedded authorization server authentication](../guides-k8s/auth-k8s.mdx#set-up-embedded-authorization-server-authentication)
466355
- For configuring token exchange, see
Lines changed: 193 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,193 @@
1+
---
2+
title: Embedded authorization server
3+
description:
4+
How the ToolHive embedded authorization server works, including the OAuth
5+
flow, token storage and forwarding, and when to use it.
6+
---
7+
8+
The embedded authorization server is an OAuth 2.0 authorization server that runs
9+
in-process within the ToolHive proxy. It solves a specific problem: how to
10+
authenticate MCP server requests to external APIs—like GitHub, Google Workspace,
11+
or Atlassian—where no federation relationship exists between your identity
12+
provider and that external service.
13+
14+
Without the embedded auth server, every MCP client would need to register its
15+
own OAuth application with each external provider, manage redirect URIs, and
16+
handle token acquisition separately. The embedded auth server centralizes this:
17+
it handles the full OAuth web flow against the external provider on behalf of
18+
clients, stores the resulting tokens, and issues its own JWTs that clients use
19+
for subsequent requests.
20+
21+
:::note
22+
23+
The embedded authorization server is currently available only for Kubernetes
24+
deployments using the ToolHive Operator.
25+
26+
:::
27+
28+
## When to use the embedded authorization server
29+
30+
Use the embedded authorization server when your MCP servers call external APIs
31+
on behalf of individual users and no federation relationship exists between your
32+
identity provider and those services.
33+
34+
| Scenario | Pattern to use |
35+
| ------------------------------------------------------------------- | -------------------------------------------------------------------------------------- |
36+
| Backend only accepts API keys or static credentials | [Static credentials](./backend-auth.mdx#static-credentials-and-api-keys) |
37+
| Backend trusts the same IdP as your clients | [Token exchange (same IdP)](./backend-auth.mdx#same-idp-with-token-exchange) |
38+
| Backend trusts a federated IdP (for example, Google Cloud, AWS) | [Token exchange (federation)](./backend-auth.mdx#federated-idps-with-identity-mapping) |
39+
| Backend is an external API with no federation (for example, GitHub) | **Embedded authorization server** (this page) |
40+
41+
## How the OAuth flow works
42+
43+
From the client's perspective, the embedded authorization server provides a
44+
standard OAuth 2.0 experience:
45+
46+
1. If the client is not yet registered, it registers via Dynamic Client
47+
Registration (DCR, RFC 7591), receiving a `client_id` and `client_secret`. No
48+
manual client registration in ToolHive is required.
49+
2. The client is directed to the ToolHive authorization endpoint.
50+
3. ToolHive redirects the client to the upstream identity provider for
51+
authentication (for example, signing in with GitHub or Atlassian).
52+
4. ToolHive exchanges the authorization code for upstream tokens and issues its
53+
own JWT to the client, signed with keys you configure.
54+
5. The client includes this JWT as a `Bearer` token in the `Authorization`
55+
header on subsequent requests.
56+
57+
```mermaid
58+
sequenceDiagram
59+
participant User
60+
participant Proxy as ToolHive Proxy
61+
participant ExtProvider as External Provider
62+
63+
User->>Proxy: Connect
64+
Proxy-->>User: Redirect to login
65+
User->>ExtProvider: Authenticate
66+
ExtProvider->>Proxy: Authorization code
67+
Proxy->>ExtProvider: Exchange code for token
68+
ExtProvider->>Proxy: Upstream tokens
69+
Proxy->>User: Issue JWT
70+
```
71+
72+
Behind the scenes, ToolHive stores the upstream tokens in session storage and
73+
uses them to authenticate MCP server requests to external APIs. The client only
74+
manages a single ToolHive-issued JWT.
75+
76+
## Token storage and forwarding
77+
78+
When the OAuth flow completes, the embedded auth server generates a unique
79+
session ID and stores the upstream tokens (access token, refresh token, and ID
80+
token from the external provider) keyed by this ID in session storage. The JWT
81+
issued to the client contains a `tsid` (Token Session ID) claim that references
82+
this session.
83+
84+
When a client makes an MCP request with this JWT:
85+
86+
1. The ToolHive proxy validates the JWT signature and extracts the `tsid` claim.
87+
2. It retrieves the upstream tokens from session storage using the `tsid`.
88+
3. The proxy replaces the `Authorization` header with the upstream access token.
89+
4. The request is forwarded to the MCP server with the external provider's
90+
token.
91+
92+
```mermaid
93+
sequenceDiagram
94+
participant Client
95+
participant Proxy as ToolHive Proxy
96+
participant Store as Session Storage
97+
participant MCP as MCP Server
98+
participant API as External API
99+
100+
Note over Client,Store: Initial OAuth flow
101+
Proxy->>Store: Store upstream tokens<br/>keyed by session ID
102+
Proxy-->>Client: Issue JWT with tsid claim
103+
104+
Note over Client,API: Subsequent MCP requests
105+
Client->>Proxy: MCP request with JWT
106+
Proxy->>Proxy: Validate JWT signature
107+
Proxy->>Store: Look up upstream token<br/>using tsid from JWT
108+
Store-->>Proxy: Return upstream access token
109+
Proxy->>MCP: Forward request with<br/>upstream access token
110+
MCP->>API: Call external API
111+
API-->>MCP: Response
112+
MCP-->>Proxy: Response
113+
Proxy-->>Client: Response
114+
```
115+
116+
MCP servers receive the upstream access token in the `Authorization: Bearer`
117+
header—they don't need to implement custom authentication logic or manage
118+
secrets.
119+
120+
## Automatic token refresh
121+
122+
Upstream access tokens expire independently of the ToolHive JWT lifespan. When
123+
the stored upstream access token has expired, ToolHive automatically refreshes
124+
it using the stored refresh token before forwarding the request. Your MCP
125+
session continues without re-authentication.
126+
127+
If the refresh token is also expired or has been revoked by the upstream
128+
provider, ToolHive returns a `401` response, prompting re-authentication through
129+
the OAuth flow.
130+
131+
## Key characteristics
132+
133+
- **In-process execution:** The authorization server runs within the ToolHive
134+
proxy—no separate infrastructure or sidecar containers needed.
135+
- **Dynamic Client Registration (DCR):** Supports OAuth 2.0 DCR (RFC 7591),
136+
allowing MCP clients to register automatically. No manual client registration
137+
in ToolHive is required.
138+
- **Direct upstream redirect:** Redirects clients directly to the upstream
139+
provider for authentication (for example, GitHub or Atlassian).
140+
- **Configurable signing keys:** JWTs are signed with keys you provide,
141+
supporting key rotation for zero-downtime updates.
142+
- **Flexible upstream providers:** Supports OIDC providers (with automatic
143+
endpoint discovery) and plain OAuth 2.0 providers (with explicit endpoint
144+
configuration).
145+
- **Configurable token lifespans:** Access tokens, refresh tokens, and
146+
authorization codes have configurable durations with sensible defaults.
147+
148+
## Session storage
149+
150+
By default, session storage is in-memory. Upstream tokens are lost when pods
151+
restart, requiring users to re-authenticate.
152+
153+
For production deployments, configure Redis Sentinel as the storage backend for
154+
persistent, highly available session storage. See
155+
[Configure session storage](../guides-k8s/auth-k8s.mdx#configure-session-storage)
156+
for a quick setup, or the full
157+
[Redis Sentinel session storage](../guides-k8s/redis-session-storage.mdx) guide
158+
for an end-to-end walkthrough.
159+
160+
## MCPServer vs. VirtualMCPServer
161+
162+
The embedded auth server is available on both `MCPServer` and `VirtualMCPServer`
163+
resources, with some differences:
164+
165+
| | MCPServer | VirtualMCPServer |
166+
| ---------------------- | ------------------------------------------- | ------------------------------------------------------------------------------ |
167+
| Configuration location | Separate `MCPExternalAuthConfig` resource | Inline `authServerConfig` block on the resource |
168+
| Upstream providers | Single upstream provider | Multiple upstream providers with sequential authorization chaining |
169+
| Token forwarding | Automatic (single provider, single backend) | Explicit `upstreamInject` or `tokenExchange` config maps providers to backends |
170+
171+
For single-backend deployments on MCPServer, the embedded auth server
172+
automatically swaps the token for each request. For vMCP with multiple backends,
173+
you configure which upstream provider's token goes to which backend using
174+
[upstream token injection](../guides-vmcp/authentication.mdx#upstream-token-injection)
175+
or
176+
[token exchange with upstream tokens](../guides-vmcp/authentication.mdx#token-exchange-with-upstream-tokens).
177+
178+
## Next steps
179+
180+
- [Set up embedded authorization server authentication](../guides-k8s/auth-k8s.mdx#set-up-embedded-authorization-server-authentication)
181+
— step-by-step setup for MCPServer resources in Kubernetes
182+
- [vMCP embedded authorization server](../guides-vmcp/authentication.mdx#embedded-authorization-server)
183+
— configuring multiple upstream providers on a VirtualMCPServer
184+
- [Redis Sentinel session storage](../guides-k8s/redis-session-storage.mdx)
185+
production session storage configuration
186+
187+
## Related information
188+
189+
- [Authentication and authorization](./auth-framework.mdx) — client-to-MCP
190+
authentication concepts and the overall framework
191+
- [Backend authentication](./backend-auth.mdx) — all backend authentication
192+
patterns, including when to choose the embedded auth server
193+
- [Cedar policies](./cedar-policies.mdx) — authorization policy configuration

0 commit comments

Comments
 (0)