Skip to content

Commit 20ecb03

Browse files
authored
Refactor/typed backend auth strategy (#2797)
* add auth/types package with typed strategy config structs Create a new leaf package pkg/vmcp/auth/types containing: - Strategy type constants (StrategyTypeUnauthenticated, etc.) - BackendAuthStrategy struct with typed fields (HeaderInjection, TokenExchange) - HeaderInjectionConfig and TokenExchangeConfig structs The Metadata field is retained in BackendAuthStrategy for backward compatibility - all existing code continues to work unchanged. Update all files to import BackendAuthStrategy from auth/types instead of config package. This is a structural refactoring with zero behavior change, preparing for a follow-up PR that will remove the Metadata field. * remove Metadata field and use typed auth config Remove the deprecated Metadata map[string]any field from BackendAuthStrategy and migrate all code to use typed fields (HeaderInjection, TokenExchange). Key changes: - Remove Metadata field from authtypes.BackendAuthStrategy - Update Strategy interface to accept *BackendAuthStrategy instead of map - Update all strategies (header_injection, tokenexchange, unauthenticated) - Update converters to return typed BackendAuthStrategy - Change Backend/BackendTarget structs to use AuthConfig instead of AuthStrategy + AuthMetadata - Update ResolveForBackend to return *BackendAuthStrategy - Update all consumers and tests This provides type safety, better IDE support, and eliminates runtime type assertions throughout the auth subsystem.
1 parent b67c42c commit 20ecb03

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+1434
-1155
lines changed

cmd/thv-operator/controllers/virtualmcpserver_vmcpconfig_test.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -213,7 +213,13 @@ func TestConvertBackendAuthConfig(t *testing.T) {
213213
assert.Equal(t, tt.expectedType, strategy.Type)
214214

215215
if tt.hasMetadata {
216-
assert.NotEmpty(t, strategy.Metadata)
216+
// For external auth config refs, check that the strategy type is set
217+
// The actual typed fields (HeaderInjection/TokenExchange) are resolved at runtime
218+
assert.Equal(t, mcpv1alpha1.BackendAuthTypeExternalAuthConfigRef, strategy.Type)
219+
} else {
220+
// For discovered auth, there should be no typed fields populated
221+
assert.Nil(t, strategy.HeaderInjection)
222+
assert.Nil(t, strategy.TokenExchange)
217223
}
218224
})
219225
}

cmd/thv-operator/pkg/vmcpconfig/converter.go

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"sigs.k8s.io/controller-runtime/pkg/log"
1010

1111
mcpv1alpha1 "github.com/stacklok/toolhive/cmd/thv-operator/api/v1alpha1"
12+
authtypes "github.com/stacklok/toolhive/pkg/vmcp/auth/types"
1213
vmcpconfig "github.com/stacklok/toolhive/pkg/vmcp/config"
1314
)
1415

@@ -155,7 +156,7 @@ func (c *Converter) convertOutgoingAuth(
155156
) *vmcpconfig.OutgoingAuthConfig {
156157
outgoing := &vmcpconfig.OutgoingAuthConfig{
157158
Source: vmcp.Spec.OutgoingAuth.Source,
158-
Backends: make(map[string]*vmcpconfig.BackendAuthStrategy),
159+
Backends: make(map[string]*authtypes.BackendAuthStrategy),
159160
}
160161

161162
// Convert Default
@@ -174,16 +175,16 @@ func (c *Converter) convertOutgoingAuth(
174175
// convertBackendAuthConfig converts BackendAuthConfig from CRD to vmcp config
175176
func (*Converter) convertBackendAuthConfig(
176177
crdConfig *mcpv1alpha1.BackendAuthConfig,
177-
) *vmcpconfig.BackendAuthStrategy {
178-
strategy := &vmcpconfig.BackendAuthStrategy{
179-
Type: crdConfig.Type,
180-
Metadata: make(map[string]any),
178+
) *authtypes.BackendAuthStrategy {
179+
strategy := &authtypes.BackendAuthStrategy{
180+
Type: crdConfig.Type,
181181
}
182182

183-
// Convert type-specific configuration to metadata
184-
if crdConfig.ExternalAuthConfigRef != nil {
185-
strategy.Metadata["externalAuthConfigRef"] = crdConfig.ExternalAuthConfigRef.Name
186-
}
183+
// Note: When Type is "external_auth_config_ref", the actual MCPExternalAuthConfig
184+
// resource should be resolved at runtime and its configuration (TokenExchange or
185+
// HeaderInjection) should be populated into the corresponding typed fields.
186+
// This conversion happens during server initialization when the referenced
187+
// MCPExternalAuthConfig can be looked up.
187188

188189
return strategy
189190
}

pkg/vmcp/aggregator/discoverer.go

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,7 @@ func (d *backendDiscoverer) applyAuthConfigToBackend(backend *vmcp.Backend, back
178178
// In discovered mode, use auth discovered from MCPServer (if any exists)
179179
// If no auth is discovered, fall back to config-based auth via ResolveForBackend
180180
// which will use backend-specific config, then Default, then no auth
181-
useDiscoveredAuth = backend.AuthStrategy != ""
181+
useDiscoveredAuth = backend.AuthConfig != nil
182182
case "inline", "":
183183
// For inline mode or empty source, always use config-based auth
184184
// Ignore any discovered auth from backends
@@ -191,14 +191,13 @@ func (d *backendDiscoverer) applyAuthConfigToBackend(backend *vmcp.Backend, back
191191

192192
if useDiscoveredAuth {
193193
// Keep the auth discovered from MCPServer (already populated in backend)
194-
logger.Debugf("Backend %s using discovered auth strategy: %s", backendName, backend.AuthStrategy)
194+
logger.Debugf("Backend %s using discovered auth strategy: %s", backendName, backend.AuthConfig.Type)
195195
} else {
196196
// Use auth from config (inline mode)
197-
authStrategy, authMetadata := d.authConfig.ResolveForBackend(backendName)
198-
if authStrategy != "" {
199-
backend.AuthStrategy = authStrategy
200-
backend.AuthMetadata = authMetadata
201-
logger.Debugf("Backend %s configured with auth strategy from config: %s", backendName, authStrategy)
197+
authConfig := d.authConfig.ResolveForBackend(backendName)
198+
if authConfig != nil {
199+
backend.AuthConfig = authConfig
200+
logger.Debugf("Backend %s configured with auth strategy from config: %s", backendName, authConfig.Type)
202201
}
203202
}
204203
}

0 commit comments

Comments
 (0)