|
| 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