-
Notifications
You must be signed in to change notification settings - Fork 201
Eliminate self-referential HTTP fetch for JWKS when using embedded auth server #4466
Description
User Story
As an embedded auth server operator, I shouldn't have to configure jwksUrl pointing my MCPServer back at itself, or enable scary-sounding flags like insecureAllowHTTP or jwksAllowPrivateIP, just to get token validation working. The embedded auth server and the token validator are running in the same process — why is there an HTTP round-trip at all?
The Pain
Today, when you enable the embedded auth server on an MCPServer, OAuth flows work — tokens are issued successfully. But token validation silently fails because the token validator tries to fetch JWKS over HTTP from the proxy's own endpoint.
To make it work, you must set either jwksAllowPrivateIP: true (if the issuer resolves to a private IP) or insecureAllowHTTP: true (if the internal service URL is http://), or both. Neither is recommended for production, and the failures are silent — requiring deep debugging to diagnose.
The fundamental issue is that the embedded auth server's KeyProvider already holds the public keys in memory. The token validator doesn't need to fetch them over HTTP. The two components just don't talk to each other directly.
What Should Happen
When embedded auth is enabled, token validation should use the in-process KeyProvider directly. No jwksUrl, no HTTP fetch, no flags. The config should be as simple as:
oidcConfig:
type: inline
inline:
issuer: https://example.com
jwksSource: embeddedOr better yet, this should be the automatic default when the embedded auth server is active.
Affected Files
pkg/networking/http_client.go—ValidatingTransport.RoundTrippkg/auth/token.go—ensureJWKSRegistered,getKeyFromJWKSpkg/runner/runner.go— runner wiring (passKeyProviderto token validator)cmd/thv-operator/api/v1alpha1/mcpserver_types.go—InlineOIDCConfigstruct
Current Workarounds
Using localhost (only insecureAllowHTTP needed):
oidcConfig:
type: inline
inline:
issuer: https://example.com
jwksUrl: http://localhost:8080/.well-known/jwks.json
insecureAllowHTTP: trueUsing the Kubernetes service name (insecureAllowHTTP + jwksAllowPrivateIP needed):
oidcConfig:
type: inline
inline:
issuer: https://example.com
jwksUrl: http://mcp-server-proxy.namespace.svc.cluster.local:8080/.well-known/jwks.json
jwksAllowPrivateIP: true
insecureAllowHTTP: trueThe service name resolves to a cluster IP (private), so it needs both flags. Localhost only needs insecureAllowHTTP.