From 6063ab7252532090752c032ffd7b05db7fb405c3 Mon Sep 17 00:00:00 2001 From: Trey Date: Mon, 13 Apr 2026 09:20:54 -0700 Subject: [PATCH 1/3] Document authServerRef field and combined auth patterns Implements changes for issue #671: - Update auth-k8s.mdx to use authServerRef as primary example in Step 5 - Add backward compatibility note for externalAuthConfigRef - Add combined embedded auth + AWS STS section in aws-sts.mdx - Add authServerRef configuration section in embedded-auth-server.mdx - Update MCPServer vs VirtualMCPServer table with authServerRef info - Add combined auth pattern reference in backend-auth.mdx --- docs/toolhive/concepts/backend-auth.mdx | 9 +++ .../concepts/embedded-auth-server.mdx | 50 ++++++++++-- docs/toolhive/guides-k8s/auth-k8s.mdx | 52 +++++++----- docs/toolhive/integrations/aws-sts.mdx | 79 +++++++++++++++++++ 4 files changed, 166 insertions(+), 24 deletions(-) diff --git a/docs/toolhive/concepts/backend-auth.mdx b/docs/toolhive/concepts/backend-auth.mdx index d02577a3..a06d1398 100644 --- a/docs/toolhive/concepts/backend-auth.mdx +++ b/docs/toolhive/concepts/backend-auth.mdx @@ -343,6 +343,15 @@ signing automatically, with claim-based IAM role selection. See the [AWS STS integration tutorial](../integrations/aws-sts.mdx) for a step-by-step setup guide. +You can also combine the embedded authorization server with AWS STS on the same +`MCPServer` or `MCPRemoteProxy` resource. In this pattern, the embedded auth +server handles incoming client authentication (using `authServerRef`), while AWS +STS handles outgoing backend credentials (using `externalAuthConfigRef`). This +is useful when your MCP clients don't have their own OIDC tokens and need +ToolHive to manage the full OAuth flow. See +[Combine embedded auth with AWS STS](../integrations/aws-sts.mdx#combine-embedded-auth-with-aws-sts) +for a complete example. + ## Related information - For client authentication concepts, see diff --git a/docs/toolhive/concepts/embedded-auth-server.mdx b/docs/toolhive/concepts/embedded-auth-server.mdx index 109bb07d..a6c8b62e 100644 --- a/docs/toolhive/concepts/embedded-auth-server.mdx +++ b/docs/toolhive/concepts/embedded-auth-server.mdx @@ -157,16 +157,48 @@ for a quick setup, or the full [Redis Sentinel session storage](../guides-k8s/redis-session-storage.mdx) guide for an end-to-end walkthrough. +## Configuring the embedded auth server with `authServerRef` + +On `MCPServer` and `MCPRemoteProxy` resources, use the `authServerRef` field to +reference an `MCPExternalAuthConfig` resource that defines the embedded auth +server. This is the preferred configuration method because it keeps the embedded +auth server (incoming client authentication) separate from +`externalAuthConfigRef` (outgoing backend authentication such as AWS STS or +token exchange). + +```yaml +spec: + authServerRef: + kind: MCPExternalAuthConfig + name: my-embedded-auth-server +``` + +The `authServerRef` field uses a `TypedLocalObjectReference`, so you must +specify both `kind: MCPExternalAuthConfig` and the `name` of the resource. + +When you only need the embedded auth server without an outgoing auth type, you +can use either `authServerRef` or `externalAuthConfigRef`. Both approaches work, +but `authServerRef` is preferred for consistency. When you need both incoming +and outgoing auth on the same resource, you must use `authServerRef` for the +embedded auth server so that `externalAuthConfigRef` remains available for the +outgoing auth configuration. + +For setup instructions, see +[Set up embedded authorization server authentication](../guides-k8s/auth-k8s.mdx#set-up-embedded-authorization-server-authentication). +For the combined auth pattern with AWS STS, see +[Combine embedded auth with AWS STS](../integrations/aws-sts.mdx#combine-embedded-auth-with-aws-sts). + ## MCPServer vs. VirtualMCPServer The embedded auth server is available on both `MCPServer` and `VirtualMCPServer` resources, with some differences: -| | MCPServer | VirtualMCPServer | -| ---------------------- | ------------------------------------------- | ------------------------------------------------------------------------------ | -| Configuration location | Separate `MCPExternalAuthConfig` resource | Inline `authServerConfig` block on the resource | -| Upstream providers | Single upstream provider | Multiple upstream providers with sequential authorization chaining | -| Token forwarding | Automatic (single provider, single backend) | Explicit `upstreamInject` or `tokenExchange` config maps providers to backends | +| | MCPServer | VirtualMCPServer | +| ---------------------- | ------------------------------------------------------------------- | ------------------------------------------------------------------------------ | +| Configuration location | `authServerRef` (preferred) or separate `MCPExternalAuthConfig` | Inline `authServerConfig` block on the resource | +| Upstream providers | Single upstream provider | Multiple upstream providers with sequential authorization chaining | +| Token forwarding | Automatic (single provider, single backend) | Explicit `upstreamInject` or `tokenExchange` config maps providers to backends | +| Combined auth | Supports `authServerRef` + `externalAuthConfigRef` on same resource | Not applicable (uses inline config) | For single-backend deployments on MCPServer, the embedded auth server automatically swaps the token for each request. For vMCP with multiple backends, @@ -175,6 +207,14 @@ you configure which upstream provider's token goes to which backend using or [token exchange with upstream tokens](../guides-vmcp/authentication.mdx#token-exchange-with-upstream-tokens). +:::note + +`VirtualMCPServer` uses an inline `authServerConfig` block, not `authServerRef`. +The `authServerRef` field is available only on `MCPServer` and `MCPRemoteProxy` +resources. + +::: + ## Next steps - [Set up embedded authorization server authentication](../guides-k8s/auth-k8s.mdx#set-up-embedded-authorization-server-authentication) diff --git a/docs/toolhive/guides-k8s/auth-k8s.mdx b/docs/toolhive/guides-k8s/auth-k8s.mdx index a2de5ad3..fd8154ee 100644 --- a/docs/toolhive/guides-k8s/auth-k8s.mdx +++ b/docs/toolhive/guides-k8s/auth-k8s.mdx @@ -609,12 +609,12 @@ kubectl apply -f embedded-auth-config.yaml **Step 5: Create the MCPServer resource** -The MCPServer needs two configuration references: `externalAuthConfigRef` -enables the embedded authorization server, and `oidcConfig` validates the JWTs -that the embedded authorization server issues. Unlike approaches 1-3 where -`oidcConfig` points to an external identity provider, here it points to the -embedded authorization server itself—the `oidcConfig` issuer must match the -`issuer` in your `MCPExternalAuthConfig`. +The MCPServer needs two configuration references: `authServerRef` enables the +embedded authorization server, and `oidcConfig` validates the JWTs that the +embedded authorization server issues. Unlike approaches 1-3 where `oidcConfig` +points to an external identity provider, here it points to the embedded +authorization server itself—the `oidcConfig` issuer must match the `issuer` in +your `MCPExternalAuthConfig`. ```yaml title="mcp-server-embedded-auth.yaml" apiVersion: toolhive.stacklok.dev/v1alpha1 @@ -629,9 +629,12 @@ spec: permissionProfile: type: builtin name: network + # highlight-start # Reference the embedded authorization server configuration - externalAuthConfigRef: + authServerRef: + kind: MCPExternalAuthConfig name: embedded-auth-server + # highlight-end # Validate JWTs issued by the embedded authorization server oidcConfig: type: inline @@ -652,33 +655,44 @@ spec: kubectl apply -f mcp-server-embedded-auth.yaml ``` +The `authServerRef` field is a `TypedLocalObjectReference` that requires both +`kind` and `name`. This field is also available on `MCPRemoteProxy` resources. + +:::info[Backward compatibility] + +You can also use `externalAuthConfigRef` with `type: embeddedAuthServer` to +configure the embedded authorization server. This approach continues to work, +but `authServerRef` is preferred because it keeps the embedded auth server +configuration separate from outgoing auth types like AWS STS or token exchange. +If you need both incoming and outgoing auth on the same resource, you must use +`authServerRef` for the embedded auth server so that `externalAuthConfigRef` +remains available for the outgoing auth configuration. + +::: + :::tip[Combining embedded auth with outgoing token exchange] -If you need both an embedded auth server for incoming client authentication -**and** an outgoing token exchange (such as AWS STS) on the same MCPServer, use -the dedicated `authServerRef` field instead of `externalAuthConfigRef` for the -embedded auth server. This separates the two configurations so they don't -compete for the same field: +Use `authServerRef` for the embedded auth server and `externalAuthConfigRef` for +outgoing auth (such as AWS STS) on the same resource. This is the primary use +case for `authServerRef`: ```yaml spec: - # Dedicated field for the embedded auth server + # Embedded auth server for incoming client authentication authServerRef: kind: MCPExternalAuthConfig name: embedded-auth-server # Outgoing token exchange (e.g., AWS STS) externalAuthConfigRef: name: aws-sts-config - kind: MCPExternalAuthConfig oidcConfig: type: inline inline: issuer: 'https://mcp.example.com' ``` -`authServerRef` and `externalAuthConfigRef` cannot both reference an -`embeddedAuthServer` type. The same `authServerRef` field is available on -MCPRemoteProxy resources. +For a complete example, see +[Combine embedded auth with AWS STS](../integrations/aws-sts.mdx#combine-embedded-auth-with-aws-sts). ::: @@ -1014,8 +1028,8 @@ kubectl logs -n toolhive-system -l app.kubernetes.io/name=weather-server-k8s - Verify the `MCPExternalAuthConfig` resource exists in the same namespace: `kubectl get mcpexternalauthconfig -n toolhive-system` -- Check that the `externalAuthConfigRef.name` in your `MCPServer` matches the - `MCPExternalAuthConfig` resource name +- Check that the `authServerRef.name` (or `externalAuthConfigRef.name`) in your + `MCPServer` matches the `MCPExternalAuthConfig` resource name - Verify the upstream provider's client ID and redirect URI are correctly configured in the `MCPExternalAuthConfig` diff --git a/docs/toolhive/integrations/aws-sts.mdx b/docs/toolhive/integrations/aws-sts.mdx index c968d5e7..eb2b3284 100644 --- a/docs/toolhive/integrations/aws-sts.mdx +++ b/docs/toolhive/integrations/aws-sts.mdx @@ -416,6 +416,85 @@ When you apply this resource, the ToolHive Operator: ::: +## Combine embedded auth with AWS STS + +If you want ToolHive to handle the full OAuth flow for incoming client +authentication (instead of validating tokens from an external OIDC provider), +you can combine the +[embedded authorization server](../concepts/embedded-auth-server.mdx) with AWS +STS on the same `MCPRemoteProxy`. Use `authServerRef` for the embedded auth +server and `externalAuthConfigRef` for the AWS STS configuration. + +This pattern is useful when your MCP clients don't have their own OIDC tokens. +The embedded auth server redirects users to an upstream identity provider (such +as Okta or Google), issues its own JWTs, and ToolHive then exchanges those JWTs +for temporary AWS credentials via STS. + +First, create an `MCPExternalAuthConfig` for the embedded auth server following +the steps in +[Set up embedded authorization server authentication](../guides-k8s/auth-k8s.mdx#set-up-embedded-authorization-server-authentication) +(steps 1 through 4). Then deploy the `MCPRemoteProxy` with both references: + +```yaml {10-12,14-15} title="aws-mcp-remote-proxy-combined.yaml" +apiVersion: toolhive.stacklok.dev/v1alpha1 +kind: MCPRemoteProxy +metadata: + name: aws-mcp-proxy + namespace: toolhive-system +spec: + remoteURL: https://aws-mcp.us-east-1.api.aws/mcp + + # Embedded auth server for incoming client authentication + authServerRef: + kind: MCPExternalAuthConfig + name: embedded-auth-server + + # AWS STS for outgoing backend authentication + externalAuthConfigRef: + name: aws-mcp-sts-auth + + # Validate JWTs issued by the embedded authorization server + oidcConfig: + type: inline + resourceUrl: https:///mcp + inline: + # This must match the issuer in your embedded auth server config + issuer: https:// + + proxyPort: 8080 + transport: streamable-http + + audit: + enabled: true + + resources: + limits: + cpu: '500m' + memory: 512Mi + requests: + cpu: 100m + memory: 128Mi +``` + +In this configuration: + +- `authServerRef` points to the `MCPExternalAuthConfig` with + `type: embeddedAuthServer`, which handles the OAuth flow for incoming clients. +- `externalAuthConfigRef` points to the `MCPExternalAuthConfig` with + `type: awsSts`, which exchanges OIDC tokens for AWS credentials on outgoing + requests. +- `oidcConfig` validates JWTs issued by the embedded auth server. The `issuer` + must match the `issuer` in your embedded auth server's + `MCPExternalAuthConfig`. + +:::info[authServerRef vs. externalAuthConfigRef] + +Without `authServerRef`, you would need to use `externalAuthConfigRef` for the +embedded auth server, leaving no way to also configure AWS STS on the same +resource. The `authServerRef` field separates these two concerns. + +::: + ## Step 5: Expose the proxy To make the proxy accessible to clients outside the cluster, create Gateway and From d99730246c10323abf1c8f89daed9deebf2ee392 Mon Sep 17 00:00:00 2001 From: Trey Date: Mon, 13 Apr 2026 09:25:53 -0700 Subject: [PATCH 2/3] Address code review feedback for authServerRef docs Co-Authored-By: Claude Opus 4.6 (1M context) --- .../toolhive/concepts/embedded-auth-server.mdx | 12 ++++++------ docs/toolhive/guides-k8s/auth-k8s.mdx | 10 ++++------ docs/toolhive/integrations/aws-sts.mdx | 18 +++++++++--------- 3 files changed, 19 insertions(+), 21 deletions(-) diff --git a/docs/toolhive/concepts/embedded-auth-server.mdx b/docs/toolhive/concepts/embedded-auth-server.mdx index a6c8b62e..78101e15 100644 --- a/docs/toolhive/concepts/embedded-auth-server.mdx +++ b/docs/toolhive/concepts/embedded-auth-server.mdx @@ -193,12 +193,12 @@ For the combined auth pattern with AWS STS, see The embedded auth server is available on both `MCPServer` and `VirtualMCPServer` resources, with some differences: -| | MCPServer | VirtualMCPServer | -| ---------------------- | ------------------------------------------------------------------- | ------------------------------------------------------------------------------ | -| Configuration location | `authServerRef` (preferred) or separate `MCPExternalAuthConfig` | Inline `authServerConfig` block on the resource | -| Upstream providers | Single upstream provider | Multiple upstream providers with sequential authorization chaining | -| Token forwarding | Automatic (single provider, single backend) | Explicit `upstreamInject` or `tokenExchange` config maps providers to backends | -| Combined auth | Supports `authServerRef` + `externalAuthConfigRef` on same resource | Not applicable (uses inline config) | +| | MCPServer | VirtualMCPServer | +| ---------------------- | ------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------ | +| Configuration location | `authServerRef` (preferred) or `externalAuthConfigRef` — both reference a separate `MCPExternalAuthConfig` resource | Inline `authServerConfig` block on the resource | +| Upstream providers | Single upstream provider | Multiple upstream providers with sequential authorization chaining | +| Token forwarding | Automatic (single provider, single backend) | Explicit `upstreamInject` or `tokenExchange` config maps providers to backends | +| Combined auth | Supports `authServerRef` + `externalAuthConfigRef` on same resource | Not applicable (uses inline config) | For single-backend deployments on MCPServer, the embedded auth server automatically swaps the token for each request. For vMCP with multiple backends, diff --git a/docs/toolhive/guides-k8s/auth-k8s.mdx b/docs/toolhive/guides-k8s/auth-k8s.mdx index fd8154ee..ba443a61 100644 --- a/docs/toolhive/guides-k8s/auth-k8s.mdx +++ b/docs/toolhive/guides-k8s/auth-k8s.mdx @@ -662,15 +662,13 @@ The `authServerRef` field is a `TypedLocalObjectReference` that requires both You can also use `externalAuthConfigRef` with `type: embeddedAuthServer` to configure the embedded authorization server. This approach continues to work, -but `authServerRef` is preferred because it keeps the embedded auth server -configuration separate from outgoing auth types like AWS STS or token exchange. -If you need both incoming and outgoing auth on the same resource, you must use -`authServerRef` for the embedded auth server so that `externalAuthConfigRef` -remains available for the outgoing auth configuration. +but `authServerRef` is preferred. For details on when and why to use each field, +see +[Configuring the embedded auth server with authServerRef](../concepts/embedded-auth-server.mdx#configuring-the-embedded-auth-server-with-authserverref). ::: -:::tip[Combining embedded auth with outgoing token exchange] +:::tip[Combining embedded auth with outgoing auth] Use `authServerRef` for the embedded auth server and `externalAuthConfigRef` for outgoing auth (such as AWS STS) on the same resource. This is the primary use diff --git a/docs/toolhive/integrations/aws-sts.mdx b/docs/toolhive/integrations/aws-sts.mdx index eb2b3284..9e28ac29 100644 --- a/docs/toolhive/integrations/aws-sts.mdx +++ b/docs/toolhive/integrations/aws-sts.mdx @@ -391,10 +391,10 @@ spec: resources: limits: cpu: '500m' - memory: 512Mi + memory: '512Mi' requests: - cpu: 100m - memory: 128Mi + cpu: '100m' + memory: '128Mi' ``` Replace the placeholders with your OIDC provider's configuration. @@ -470,10 +470,10 @@ spec: resources: limits: cpu: '500m' - memory: 512Mi + memory: '512Mi' requests: - cpu: 100m - memory: 128Mi + cpu: '100m' + memory: '128Mi' ``` In this configuration: @@ -489,9 +489,9 @@ In this configuration: :::info[authServerRef vs. externalAuthConfigRef] -Without `authServerRef`, you would need to use `externalAuthConfigRef` for the -embedded auth server, leaving no way to also configure AWS STS on the same -resource. The `authServerRef` field separates these two concerns. +The `authServerRef` field separates embedded auth from outgoing auth concerns. +For more details, see +[Configuring the embedded auth server with authServerRef](../concepts/embedded-auth-server.mdx#configuring-the-embedded-auth-server-with-authserverref). ::: From d57722fe18060ae79ad922a633ed32f8359eeae0 Mon Sep 17 00:00:00 2001 From: Trey Date: Mon, 13 Apr 2026 09:40:43 -0700 Subject: [PATCH 3/3] Minor manual tweaks --- docs/toolhive/concepts/embedded-auth-server.mdx | 12 ++++++------ docs/toolhive/guides-k8s/auth-k8s.mdx | 3 +-- docs/toolhive/integrations/aws-sts.mdx | 8 -------- 3 files changed, 7 insertions(+), 16 deletions(-) diff --git a/docs/toolhive/concepts/embedded-auth-server.mdx b/docs/toolhive/concepts/embedded-auth-server.mdx index 78101e15..f99b77cb 100644 --- a/docs/toolhive/concepts/embedded-auth-server.mdx +++ b/docs/toolhive/concepts/embedded-auth-server.mdx @@ -176,12 +176,12 @@ spec: The `authServerRef` field uses a `TypedLocalObjectReference`, so you must specify both `kind: MCPExternalAuthConfig` and the `name` of the resource. -When you only need the embedded auth server without an outgoing auth type, you -can use either `authServerRef` or `externalAuthConfigRef`. Both approaches work, -but `authServerRef` is preferred for consistency. When you need both incoming -and outgoing auth on the same resource, you must use `authServerRef` for the -embedded auth server so that `externalAuthConfigRef` remains available for the -outgoing auth configuration. +The `authServerRef` field is the preferred way to configure the embedded auth +server. Using `externalAuthConfigRef` with `type: embeddedAuthServer` is +maintained for backward compatibility. When you need both incoming and outgoing +auth on the same resource, you must use `authServerRef` for the embedded auth +server so that `externalAuthConfigRef` remains available for the outgoing auth +configuration. For setup instructions, see [Set up embedded authorization server authentication](../guides-k8s/auth-k8s.mdx#set-up-embedded-authorization-server-authentication). diff --git a/docs/toolhive/guides-k8s/auth-k8s.mdx b/docs/toolhive/guides-k8s/auth-k8s.mdx index ba443a61..334b09ad 100644 --- a/docs/toolhive/guides-k8s/auth-k8s.mdx +++ b/docs/toolhive/guides-k8s/auth-k8s.mdx @@ -671,8 +671,7 @@ see :::tip[Combining embedded auth with outgoing auth] Use `authServerRef` for the embedded auth server and `externalAuthConfigRef` for -outgoing auth (such as AWS STS) on the same resource. This is the primary use -case for `authServerRef`: +outgoing auth (such as AWS STS) on the same resource: ```yaml spec: diff --git a/docs/toolhive/integrations/aws-sts.mdx b/docs/toolhive/integrations/aws-sts.mdx index 9e28ac29..6e86216b 100644 --- a/docs/toolhive/integrations/aws-sts.mdx +++ b/docs/toolhive/integrations/aws-sts.mdx @@ -487,14 +487,6 @@ In this configuration: must match the `issuer` in your embedded auth server's `MCPExternalAuthConfig`. -:::info[authServerRef vs. externalAuthConfigRef] - -The `authServerRef` field separates embedded auth from outgoing auth concerns. -For more details, see -[Configuring the embedded auth server with authServerRef](../concepts/embedded-auth-server.mdx#configuring-the-embedded-auth-server-with-authserverref). - -::: - ## Step 5: Expose the proxy To make the proxy accessible to clients outside the cluster, create Gateway and