Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions cmd/thv-operator/api/v1beta1/mcpexternalauthconfig_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,16 @@ type EmbeddedAuthServerConfig struct {
// +optional
Storage *AuthServerStorageConfig `json:"storage,omitempty"`

// DisableUpstreamTokenInjection prevents the embedded auth server from injecting
// upstream IdP tokens into requests forwarded to the backend MCP server.
// When true, the embedded auth server still handles OAuth flows for clients
// but does not swap ToolHive JWTs for upstream tokens on outgoing requests.
// This is useful when the backend MCP server does not require authentication
// (e.g., public documentation servers) but you still want client authentication.
// +kubebuilder:default=false
// +optional
DisableUpstreamTokenInjection bool `json:"disableUpstreamTokenInjection,omitempty"`

// AllowedAudiences is the list of valid resource URIs that tokens can be issued for.
// For an embedded auth server, this can be determined by the servers (MCP or vMCP) it serves.

Expand Down
3 changes: 3 additions & 0 deletions cmd/thv-operator/pkg/controllerutil/authserver.go
Original file line number Diff line number Diff line change
Expand Up @@ -581,6 +581,9 @@ func BuildAuthServerRunConfig(
}
config.Storage = storageCfg

// Wire through upstream token injection flag
config.DisableUpstreamTokenInjection = authConfig.DisableUpstreamTokenInjection

return config, nil
}

Expand Down
39 changes: 39 additions & 0 deletions cmd/thv-operator/pkg/controllerutil/authserver_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1423,6 +1423,45 @@ func TestBuildAuthServerRunConfig(t *testing.T) {
"DCRConfig should remain nil when only ClientID is set")
},
},
{
name: "DisableUpstreamTokenInjection is wired through",
authConfig: &mcpv1beta1.EmbeddedAuthServerConfig{
Issuer: "https://auth.example.com",
SigningKeySecretRefs: []mcpv1beta1.SecretKeyRef{
{Name: "signing-key", Key: "private.pem"},
},
HMACSecretRefs: []mcpv1beta1.SecretKeyRef{
{Name: "hmac-secret", Key: "hmac"},
},
DisableUpstreamTokenInjection: true,
},
allowedAudiences: defaultAudiences,
scopesSupported: defaultScopes,
checkFunc: func(t *testing.T, config *authserver.RunConfig) {
t.Helper()
assert.True(t, config.DisableUpstreamTokenInjection,
"DisableUpstreamTokenInjection should be wired from CRD to RunConfig")
},
},
{
name: "DisableUpstreamTokenInjection defaults to false",
authConfig: &mcpv1beta1.EmbeddedAuthServerConfig{
Issuer: "https://auth.example.com",
SigningKeySecretRefs: []mcpv1beta1.SecretKeyRef{
{Name: "signing-key", Key: "private.pem"},
},
HMACSecretRefs: []mcpv1beta1.SecretKeyRef{
{Name: "hmac-secret", Key: "hmac"},
},
},
allowedAudiences: defaultAudiences,
scopesSupported: defaultScopes,
checkFunc: func(t *testing.T, config *authserver.RunConfig) {
t.Helper()
assert.False(t, config.DisableUpstreamTokenInjection,
"DisableUpstreamTokenInjection should default to false")
},
},
}

for _, tt := range tests {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,16 @@ spec:
Must be a valid HTTPS URL (or HTTP for localhost) without query, fragment, or trailing slash.
pattern: ^https?://[^\s?#]+[^/\s?#]$
type: string
disableUpstreamTokenInjection:
default: false
description: |-
DisableUpstreamTokenInjection prevents the embedded auth server from injecting
upstream IdP tokens into requests forwarded to the backend MCP server.
When true, the embedded auth server still handles OAuth flows for clients
but does not swap ToolHive JWTs for upstream tokens on outgoing requests.
This is useful when the backend MCP server does not require authentication
(e.g., public documentation servers) but you still want client authentication.
type: boolean
hmacSecretRefs:
description: |-
HMACSecretRefs references Kubernetes Secrets containing symmetric secrets for signing
Expand Down Expand Up @@ -1385,6 +1395,16 @@ spec:
Must be a valid HTTPS URL (or HTTP for localhost) without query, fragment, or trailing slash.
pattern: ^https?://[^\s?#]+[^/\s?#]$
type: string
disableUpstreamTokenInjection:
default: false
description: |-
DisableUpstreamTokenInjection prevents the embedded auth server from injecting
upstream IdP tokens into requests forwarded to the backend MCP server.
When true, the embedded auth server still handles OAuth flows for clients
but does not swap ToolHive JWTs for upstream tokens on outgoing requests.
This is useful when the backend MCP server does not require authentication
(e.g., public documentation servers) but you still want client authentication.
type: boolean
hmacSecretRefs:
description: |-
HMACSecretRefs references Kubernetes Secrets containing symmetric secrets for signing
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,16 @@ spec:
Must be a valid HTTPS URL (or HTTP for localhost) without query, fragment, or trailing slash.
pattern: ^https?://[^\s?#]+[^/\s?#]$
type: string
disableUpstreamTokenInjection:
default: false
description: |-
DisableUpstreamTokenInjection prevents the embedded auth server from injecting
upstream IdP tokens into requests forwarded to the backend MCP server.
When true, the embedded auth server still handles OAuth flows for clients
but does not swap ToolHive JWTs for upstream tokens on outgoing requests.
This is useful when the backend MCP server does not require authentication
(e.g., public documentation servers) but you still want client authentication.
type: boolean
hmacSecretRefs:
description: |-
HMACSecretRefs references Kubernetes Secrets containing symmetric secrets for signing
Expand Down Expand Up @@ -2723,6 +2733,16 @@ spec:
Must be a valid HTTPS URL (or HTTP for localhost) without query, fragment, or trailing slash.
pattern: ^https?://[^\s?#]+[^/\s?#]$
type: string
disableUpstreamTokenInjection:
default: false
description: |-
DisableUpstreamTokenInjection prevents the embedded auth server from injecting
upstream IdP tokens into requests forwarded to the backend MCP server.
When true, the embedded auth server still handles OAuth flows for clients
but does not swap ToolHive JWTs for upstream tokens on outgoing requests.
This is useful when the backend MCP server does not require authentication
(e.g., public documentation servers) but you still want client authentication.
type: boolean
hmacSecretRefs:
description: |-
HMACSecretRefs references Kubernetes Secrets containing symmetric secrets for signing
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,16 @@ spec:
Must be a valid HTTPS URL (or HTTP for localhost) without query, fragment, or trailing slash.
pattern: ^https?://[^\s?#]+[^/\s?#]$
type: string
disableUpstreamTokenInjection:
default: false
description: |-
DisableUpstreamTokenInjection prevents the embedded auth server from injecting
upstream IdP tokens into requests forwarded to the backend MCP server.
When true, the embedded auth server still handles OAuth flows for clients
but does not swap ToolHive JWTs for upstream tokens on outgoing requests.
This is useful when the backend MCP server does not require authentication
(e.g., public documentation servers) but you still want client authentication.
type: boolean
hmacSecretRefs:
description: |-
HMACSecretRefs references Kubernetes Secrets containing symmetric secrets for signing
Expand Down Expand Up @@ -1388,6 +1398,16 @@ spec:
Must be a valid HTTPS URL (or HTTP for localhost) without query, fragment, or trailing slash.
pattern: ^https?://[^\s?#]+[^/\s?#]$
type: string
disableUpstreamTokenInjection:
default: false
description: |-
DisableUpstreamTokenInjection prevents the embedded auth server from injecting
upstream IdP tokens into requests forwarded to the backend MCP server.
When true, the embedded auth server still handles OAuth flows for clients
but does not swap ToolHive JWTs for upstream tokens on outgoing requests.
This is useful when the backend MCP server does not require authentication
(e.g., public documentation servers) but you still want client authentication.
type: boolean
hmacSecretRefs:
description: |-
HMACSecretRefs references Kubernetes Secrets containing symmetric secrets for signing
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,16 @@ spec:
Must be a valid HTTPS URL (or HTTP for localhost) without query, fragment, or trailing slash.
pattern: ^https?://[^\s?#]+[^/\s?#]$
type: string
disableUpstreamTokenInjection:
default: false
description: |-
DisableUpstreamTokenInjection prevents the embedded auth server from injecting
upstream IdP tokens into requests forwarded to the backend MCP server.
When true, the embedded auth server still handles OAuth flows for clients
but does not swap ToolHive JWTs for upstream tokens on outgoing requests.
This is useful when the backend MCP server does not require authentication
(e.g., public documentation servers) but you still want client authentication.
type: boolean
hmacSecretRefs:
description: |-
HMACSecretRefs references Kubernetes Secrets containing symmetric secrets for signing
Expand Down Expand Up @@ -2726,6 +2736,16 @@ spec:
Must be a valid HTTPS URL (or HTTP for localhost) without query, fragment, or trailing slash.
pattern: ^https?://[^\s?#]+[^/\s?#]$
type: string
disableUpstreamTokenInjection:
default: false
description: |-
DisableUpstreamTokenInjection prevents the embedded auth server from injecting
upstream IdP tokens into requests forwarded to the backend MCP server.
When true, the embedded auth server still handles OAuth flows for clients
but does not swap ToolHive JWTs for upstream tokens on outgoing requests.
This is useful when the backend MCP server does not require authentication
(e.g., public documentation servers) but you still want client authentication.
type: boolean
hmacSecretRefs:
description: |-
HMACSecretRefs references Kubernetes Secrets containing symmetric secrets for signing
Expand Down
1 change: 1 addition & 0 deletions docs/operator/crd-api.md

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions docs/server/docs.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions docs/server/swagger.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions docs/server/swagger.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions pkg/authserver/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,12 @@ type RunConfig struct {
// Storage configures the storage backend for the auth server.
// If nil, defaults to in-memory storage.
Storage *storage.RunConfig `json:"storage,omitempty" yaml:"storage,omitempty"`

// DisableUpstreamTokenInjection prevents the upstream swap middleware from being added.
// When true, the embedded auth server handles OAuth flows for clients but does not
// inject upstream IdP tokens into requests forwarded to the backend MCP server.
//nolint:lll // field tags require full JSON+YAML names
DisableUpstreamTokenInjection bool `json:"disable_upstream_token_injection,omitempty" yaml:"disable_upstream_token_injection,omitempty"`
}

// SigningKeyRunConfig configures where to load signing keys from.
Expand Down
Loading
Loading