You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Add an optional embedded OAuth authorization server (AS) to vMCP. When enabled, the AS acts as the OIDC issuer for incoming clients: it drives users through one or more upstream IDPs, accumulates their tokens, and issues a ToolHive JWT. The OIDC middleware validates that TH-JWT via a self-referencing loopback and eagerly loads the upstream tokens into `identity.UpstreamTokens`. Existing behavior when no AS is configured (Mode A) is byte-for-byte unchanged.
Background
vMCP today requires clients to obtain upstream IDP tokens externally before connecting — there is no mechanism for vMCP to orchestrate the auth flow itself. Additionally, upstream tokens accumulated during login have no unified path into the outgoing auth layer; the `upstream_inject` strategy (which would inject an upstream provider token into backend requests) has no source to draw from.
This RFC adds Mode B, where vMCP hosts the auth server at the same origin, handles OAuth/OIDC discovery as a loopback, and makes upstream tokens available to outgoing auth strategies via `identity.UpstreamTokens`.
Phase 1 is the root; Phases 2 and 3 can be developed in parallel; Phase 4 is the integration phase.
Acceptance Criteria
vMCP can be configured with an embedded AS (authServer.runConfig in YAML; spec.authServerConfigRef in K8s) and serves OAuth/OIDC endpoints at the same origin
/.well-known/openid-configuration, /.well-known/oauth-authorization-server, /.well-known/jwks.json, and /oauth/ are mounted as unauthenticated routes in Mode B; Mode A is unaffected
The /.well-known/ catch-all handler is replaced with an explicit /.well-known/oauth-protected-resource registration (non-breaking)
Validation rules V-01..V-07 are enforced at startup (YAML path) and at operator reconciliation (K8s path), producing actionable error messages
The operator reconciler resolves spec.authServerConfigRef, validates type and issuer consistency, and surfaces an AuthServerConfigValid status condition
Mode A behavior is byte-for-byte identical to today — all new code paths are gated on cfg.AuthServer != nil
Overview
Add an optional embedded OAuth authorization server (AS) to vMCP. When enabled, the AS acts as the OIDC issuer for incoming clients: it drives users through one or more upstream IDPs, accumulates their tokens, and issues a ToolHive JWT. The OIDC middleware validates that TH-JWT via a self-referencing loopback and eagerly loads the upstream tokens into `identity.UpstreamTokens`. Existing behavior when no AS is configured (Mode A) is byte-for-byte unchanged.
Background
vMCP today requires clients to obtain upstream IDP tokens externally before connecting — there is no mechanism for vMCP to orchestrate the auth flow itself. Additionally, upstream tokens accumulated during login have no unified path into the outgoing auth layer; the `upstream_inject` strategy (which would inject an upstream provider token into backend requests) has no source to draw from.
This RFC adds Mode B, where vMCP hosts the auth server at the same origin, handles OAuth/OIDC discovery as a loopback, and makes upstream tokens available to outgoing auth strategies via `identity.UpstreamTokens`.
RFC: stacklok/toolhive-rfcs#53
Depends on: #3924 (RFC-0052 multi-upstream IDP support) for full end-to-end token flow
Task Breakdown
Phase 1 is the root; Phases 2 and 3 can be developed in parallel; Phase 4 is the integration phase.
Acceptance Criteria
authServer.runConfigin YAML;spec.authServerConfigRefin K8s) and serves OAuth/OIDC endpoints at the same origin/.well-known/openid-configuration,/.well-known/oauth-authorization-server,/.well-known/jwks.json, and/oauth/are mounted as unauthenticated routes in Mode B; Mode A is unaffected/.well-known/catch-all handler is replaced with an explicit/.well-known/oauth-protected-resourceregistration (non-breaking)spec.authServerConfigRef, validates type and issuer consistency, and surfaces anAuthServerConfigValidstatus conditioncfg.AuthServer != nil