@@ -159,145 +159,26 @@ When the MCP server needs to call an external API where no federation
159159relationship exists—such as GitHub, Google Workspace, or Atlassian APIs—the
160160embedded authorization server handles the full OAuth web flow against the
161161external 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
184165The embedded authorization server runs in-process within the ToolHive proxy—no
185166separate infrastructure is needed. It supports Dynamic Client Registration
186167(DCR), so MCP clients can register automatically with ToolHive—no manual client
187168configuration 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
191177The embedded authorization server is currently available only for Kubernetes
192178deployments 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:** Currently supports one upstream identity
215- provider per configuration.
216-
217- :::info[ Chained authentication not yet supported]
218-
219- The embedded authorization server redirects clients directly to the upstream
220- provider. This means the upstream provider must be the service whose API the MCP
221- server calls. Chained authentication—where a client authenticates with a
222- corporate IdP like Okta, which then federates to an external provider like
223- GitHub—is not yet supported. If your deployment requires this pattern, consider
224- using [ token exchange] ( #same-idp-with-token-exchange ) with a federated identity
225- provider instead.
226-
227- :::
228-
229- #### Token storage and forwarding
230-
231- The embedded authorization server stores upstream tokens (access tokens, refresh
232- tokens, and ID tokens from external providers) in session storage. When the
233- OAuth flow completes, the server generates a unique session ID and stores the
234- upstream tokens keyed by this ID. The JWT issued to the client contains a ` tsid `
235- (Token Session ID) claim that references this session.
236-
237- When a client makes an MCP request with this JWT:
238-
239- 1 . The ToolHive proxy validates the JWT signature and extracts the ` tsid ` claim
240- 2 . It retrieves the upstream tokens from session storage using the ` tsid `
241- 3 . The proxy replaces the ` Authorization ` header with the upstream access token
242- 4 . The request is forwarded to the MCP server with the external provider's token
243-
244- ``` mermaid
245- sequenceDiagram
246- participant Client
247- participant Proxy as ToolHive Proxy
248- participant Store as Session Storage
249- participant MCP as MCP Server
250- participant API as External API
251-
252- Note over Client,Store: Initial OAuth flow
253- Proxy->>Store: Store upstream tokens<br/>keyed by session ID
254- Proxy-->>Client: Issue JWT with tsid claim
255-
256- Note over Client,API: Subsequent MCP requests
257- Client->>Proxy: MCP request with JWT
258- Proxy->>Proxy: Validate JWT signature
259- Proxy->>Store: Look up upstream token<br/>using tsid from JWT
260- Store-->>Proxy: Return upstream access token
261- Proxy->>MCP: Forward request with<br/>upstream access token
262- MCP->>API: Call external API
263- API-->>MCP: Response
264- MCP-->>Proxy: Response
265- Proxy-->>Client: Response
266- ```
267-
268- This mechanism allows MCP servers to call external APIs with the user's actual
269- credentials from the upstream provider, while the client only needs to manage a
270- single ToolHive-issued JWT.
271-
272- #### Automatic token refresh
273-
274- Upstream access tokens have their own expiration, independent of the ToolHive
275- JWT lifespan. When the stored upstream access token has expired, ToolHive
276- automatically refreshes it using the stored refresh token before forwarding the
277- request — your MCP session continues without re-authentication.
278-
279- If the refresh token is also expired or has been revoked by the upstream
280- provider, ToolHive returns a ` 401 ` response, prompting you to re-authenticate
281- through the OAuth flow.
282-
283- :::warning[ Session storage limitations]
284-
285- By default, session storage is in-memory only. Upstream tokens are lost when
286- pods restart, requiring users to re-authenticate. For production deployments,
287- configure Redis Sentinel as the storage backend for persistent, highly available
288- session storage. See
289- [ Configure session storage] ( ../guides-k8s/auth-k8s.mdx#configure-session-storage )
290- for a quick setup, or the full
291- [ Redis Sentinel session storage] ( ../guides-k8s/redis-session-storage.mdx )
292- tutorial for an end-to-end walkthrough.
293-
294- :::
295-
296- For the client-facing OAuth flow, see
297- [ Embedded authorization server] ( ./auth-framework.mdx#embedded-authorization-server ) .
298- For Kubernetes setup instructions, see
299- [ Set up embedded authorization server authentication] ( ../guides-k8s/auth-k8s.mdx#set-up-embedded-authorization-server-authentication ) .
300-
301182## Token exchange in depth
302183
303184This section provides implementation details for the token exchange patterns
@@ -467,8 +348,8 @@ setup guide.
467348
468349- For client authentication concepts, see
469350 [ Authentication and authorization] ( ./auth-framework.mdx )
470- - For the embedded authorization server, see
471- [ 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 )
472353- For configuring the embedded authorization server in Kubernetes, see
473354 [ Set up embedded authorization server authentication] ( ../guides-k8s/auth-k8s.mdx#set-up-embedded-authorization-server-authentication )
474355- For configuring token exchange, see
0 commit comments