Documentation
¶
Overview ¶
Package strategies provides authentication strategy implementations for Virtual MCP Server.
Package strategies provides authentication strategy implementations for Virtual MCP Server.
Index ¶
Constants ¶
const ( // MetadataHeaderName is the key for the HTTP header name in metadata. // Used by HeaderInjectionStrategy to identify which header to inject. MetadataHeaderName = "header_name" // MetadataHeaderValue is the key for the HTTP header value in metadata. // Used by HeaderInjectionStrategy to identify the value to inject. MetadataHeaderValue = "header_value" // MetadataHeaderValueEnv is the key for the environment variable name // that contains the header value. Used by converters during the conversion // phase to indicate that secret resolution is needed. This is replaced with // MetadataHeaderValue (containing the actual secret) before reaching the strategy. MetadataHeaderValueEnv = "header_value_env" )
Metadata key names used in strategy configurations.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type AwsStsStrategy ¶ added in v0.26.0
type AwsStsStrategy struct {
// contains filtered or unexported fields
}
AwsStsStrategy authenticates backend requests using AWS STS token exchange and SigV4 signing.
For each authenticated request, the strategy:
- Extracts the bearer token and JWT claims from the incoming identity
- Selects the appropriate IAM role using a CEL-based role mapper
- Exchanges the identity token for temporary AWS credentials via AssumeRoleWithWebIdentity
- Signs the outgoing request with SigV4 using the temporary credentials
Required configuration fields (in BackendAuthStrategy.AwsSts):
- Region: AWS region for STS endpoint and SigV4 signing
At least one of the following must also be configured:
- FallbackRoleArn: IAM role ARN to assume when no role mappings match
- RoleMappings: CEL-based rules for mapping JWT claims to IAM roles
This strategy is appropriate when:
- The backend is an AWS-managed MCP server requiring SigV4 authentication
- Role selection should be derived from the incoming caller's JWT claims
The strategy is safe for concurrent use. It maintains a per-config cache of roleMapper and exchanger instances, keyed by a SHA-256 hash over all fields of the AwsStsConfig (region, service, role mappings including Claim/Matcher/Priority, fallback ARN, and session claims). Cache entries are created on first use (via Validate or Authenticate) and shared across all requests with the same configuration.
func NewAwsStsStrategy ¶ added in v0.26.0
func NewAwsStsStrategy() *AwsStsStrategy
NewAwsStsStrategy creates a new AwsStsStrategy instance.
func (*AwsStsStrategy) Authenticate ¶ added in v0.26.0
func (s *AwsStsStrategy) Authenticate( ctx context.Context, req *http.Request, strategy *authtypes.BackendAuthStrategy, ) error
Authenticate performs AWS STS token exchange and SigV4 signing for the request.
This method:
- Skips authentication for health check requests (no user identity to use)
- Builds an awssts.Config from the strategy configuration
- Delegates to authenticateWithConfig to perform the STS exchange and signing
Parameters:
- ctx: Request context containing the authenticated identity (or health check marker)
- req: The HTTP request to authenticate; modified in place with SigV4 headers
- strategy: Backend auth strategy containing AwsSts configuration
Returns an error if:
- The AwsSts configuration is nil or missing a required field
- No identity is found in the context
- Role selection fails (no matching mapping and no fallback)
- The STS exchange fails
- SigV4 signing fails
func (*AwsStsStrategy) Name ¶ added in v0.26.0
func (*AwsStsStrategy) Name() string
Name returns the strategy identifier.
func (*AwsStsStrategy) Validate ¶ added in v0.26.0
func (s *AwsStsStrategy) Validate(strategy *authtypes.BackendAuthStrategy) error
Validate checks if the required strategy configuration fields are present and valid, and warms the per-config cache entry for this backend.
This method verifies that:
- The AwsSts configuration block is present
- Region is non-empty (required for STS endpoint and SigV4 signing)
- The configuration is structurally valid (delegates to awssts.ValidateConfig)
type HeaderInjectionStrategy ¶
type HeaderInjectionStrategy struct{}
HeaderInjectionStrategy injects a static header value into request headers. This is a general-purpose strategy that can inject any header with any value, commonly used for API keys, bearer tokens, or custom authentication headers.
The strategy extracts the header name and value from the typed HeaderInjection configuration and injects them into the backend request headers.
Required configuration fields (in BackendAuthStrategy.HeaderInjection):
- HeaderName: The HTTP header name to use (e.g., "X-API-Key", "Authorization")
- HeaderValue: The header value to inject (can be an API key, token, or any value) Note: In YAML configuration, use either header_value (literal) or header_value_env (from environment). The value is resolved at config load time and passed here as HeaderValue.
This strategy is appropriate when:
- The backend requires a static header value for authentication
- The header value is stored securely in the vMCP configuration
- No dynamic token exchange or user-specific authentication is required
Future enhancements may include:
- Support for multiple header formats (e.g., "Bearer <key>")
- Value rotation and refresh mechanisms
func NewHeaderInjectionStrategy ¶
func NewHeaderInjectionStrategy() *HeaderInjectionStrategy
NewHeaderInjectionStrategy creates a new HeaderInjectionStrategy instance.
func (*HeaderInjectionStrategy) Authenticate ¶
func (*HeaderInjectionStrategy) Authenticate( _ context.Context, req *http.Request, strategy *authtypes.BackendAuthStrategy, ) error
Authenticate injects the header value from the strategy config into the request header.
This method:
- Validates that HeaderName and HeaderValue are present in the strategy config
- Sets the specified header with the provided value
This strategy applies to all requests including health checks, since the header value is static and does not depend on user identity.
Parameters:
- ctx: Request context
- req: The HTTP request to authenticate
- strategy: The backend auth strategy configuration containing HeaderInjection
Returns an error if:
- HeaderName is missing or empty
- HeaderValue is missing or empty
func (*HeaderInjectionStrategy) Name ¶
func (*HeaderInjectionStrategy) Name() string
Name returns the strategy identifier.
func (*HeaderInjectionStrategy) Validate ¶
func (*HeaderInjectionStrategy) Validate(strategy *authtypes.BackendAuthStrategy) error
Validate checks if the required strategy configuration fields are present and valid.
This method verifies that:
- HeaderName is present and non-empty
- HeaderValue is present and non-empty
- HeaderName is a valid HTTP header name (prevents CRLF injection)
- HeaderValue is a valid HTTP header value (prevents CRLF injection)
This validation is typically called during configuration parsing to fail fast if the strategy is misconfigured.
type TokenExchangeStrategy ¶ added in v0.6.3
type TokenExchangeStrategy struct {
// contains filtered or unexported fields
}
TokenExchangeStrategy exchanges the client's token for a backend-specific token using RFC 8693 token exchange protocol.
This strategy implements OAuth 2.0 Token Exchange (RFC 8693) to convert a client's token into a backend-specific token that the backend MCP server can validate.
The strategy caches ExchangeConfig instances per backend configuration to avoid recreating configuration objects. Per-user token caching is handled by the upper vMCP TokenCache layer.
Required metadata fields:
- token_url: The OAuth 2.0 token endpoint URL for token exchange
Optional metadata fields:
- client_id: OAuth 2.0 client identifier (required for some token endpoints)
- client_secret: OAuth 2.0 client secret (directly provided, mutually exclusive with client_secret_env)
- client_secret_env: Name of environment variable containing the client secret (mutually exclusive with client_secret)
- audience: Target audience for the exchanged token
- scopes: Array of scope strings to request
- subject_token_type: Type of the subject token (default: "access_token")
This strategy is appropriate when:
- The backend uses a different identity provider than the vMCP server
- Token exchange relationships are configured between the identity providers
- Per-user token exchange is required (not static credentials)
func NewTokenExchangeStrategy ¶ added in v0.6.3
func NewTokenExchangeStrategy(envReader env.Reader) *TokenExchangeStrategy
NewTokenExchangeStrategy creates a new TokenExchangeStrategy instance.
func (*TokenExchangeStrategy) Authenticate ¶ added in v0.6.3
func (s *TokenExchangeStrategy) Authenticate( ctx context.Context, req *http.Request, strategy *authtypes.BackendAuthStrategy, ) error
Authenticate exchanges the client's token for a backend token and injects it.
This method:
- Parses and validates the token exchange configuration from strategy
- For health check requests: uses a client credentials grant if client_id and client_secret are configured; otherwise skips authentication
- For regular requests: retrieves the client's identity and token from the context, gets or creates a cached ExchangeConfig, performs the token exchange, and injects the token into the backend request's Authorization header
Token caching per user is handled by the upper vMCP TokenCache layer. This strategy only caches the ExchangeConfig template per backend.
Parameters:
- ctx: Request context containing the authenticated identity (or health check marker)
- req: The HTTP request to authenticate
- strategy: Backend auth strategy containing token exchange configuration
Returns an error if:
- Strategy configuration is invalid or incomplete
- No identity is found in the context (regular requests only)
- The identity has no token (regular requests only)
- Token exchange or client credentials grant fails
func (*TokenExchangeStrategy) Name ¶ added in v0.6.3
func (*TokenExchangeStrategy) Name() string
Name returns the strategy identifier.
func (*TokenExchangeStrategy) Validate ¶ added in v0.6.3
func (s *TokenExchangeStrategy) Validate(strategy *authtypes.BackendAuthStrategy) error
Validate checks if the required configuration fields are present and valid.
This method verifies that:
- TokenURL is present and valid
- Optional fields (if present) have correct types and values
- ClientSecret is only provided when ClientID is present
This validation is typically called during configuration parsing to fail fast if the strategy is misconfigured.
type UnauthenticatedStrategy ¶
type UnauthenticatedStrategy struct{}
UnauthenticatedStrategy is a no-op authentication strategy that performs no authentication. This strategy is used when a backend MCP server requires no authentication.
Unlike passing a nil authenticator (which is now an error), this strategy makes the intent explicit: "this backend intentionally has no authentication".
The strategy performs no modifications to requests and validates all metadata.
This is appropriate when:
- The backend MCP server is on a trusted network (e.g., localhost)
- The backend has no authentication requirements
- Authentication is handled by network-level security (e.g., VPC, firewall)
Security Warning: Only use this strategy when you are certain the backend requires no authentication. For production deployments, prefer explicit authentication strategies (header_injection, token_exchange).
Configuration: No metadata required, but any metadata is accepted and ignored.
Example configuration:
backends:
local-backend:
strategy: "unauthenticated"
func NewUnauthenticatedStrategy ¶
func NewUnauthenticatedStrategy() *UnauthenticatedStrategy
NewUnauthenticatedStrategy creates a new UnauthenticatedStrategy instance.
func (*UnauthenticatedStrategy) Authenticate ¶
func (*UnauthenticatedStrategy) Authenticate(_ context.Context, _ *http.Request, _ *authtypes.BackendAuthStrategy) error
Authenticate performs no authentication and returns immediately.
This method:
- Does not modify the request in any way
- Always returns nil (success)
Parameters:
- ctx: Request context (unused)
- req: The HTTP request (not modified)
- config: Strategy configuration (ignored)
Returns nil (always succeeds).
func (*UnauthenticatedStrategy) Name ¶
func (*UnauthenticatedStrategy) Name() string
Name returns the strategy identifier.
func (*UnauthenticatedStrategy) Validate ¶
func (*UnauthenticatedStrategy) Validate(_ *authtypes.BackendAuthStrategy) error
Validate checks if the strategy configuration is valid.
UnauthenticatedStrategy accepts any configuration (including nil or empty), so this always returns nil.
This permissive validation allows the strategy to be used without configuration or with arbitrary configuration that may be present for documentation purposes.
type UpstreamInjectStrategy ¶ added in v0.14.0
type UpstreamInjectStrategy struct{}
UpstreamInjectStrategy injects an upstream IDP token into backend request headers. The token is obtained by the embedded authorization server during the OAuth flow and stored in identity.UpstreamTokens, keyed by provider name.
This strategy looks up the provider-specific token from the authenticated identity and sets it as a Bearer token in the Authorization header of the backend request.
Required configuration fields (in BackendAuthStrategy.UpstreamInject):
- ProviderName: The upstream provider name matching an entry in AuthServer.Upstreams. The token for this provider must be present in the identity's UpstreamTokens map.
This strategy is appropriate when:
- The backend requires a user-specific upstream IDP token for authentication
- The embedded authorization server has been configured to obtain tokens from the upstream provider during the OAuth flow
- The upstream token should be passed through to the backend as-is (no exchange)
func NewUpstreamInjectStrategy ¶ added in v0.14.0
func NewUpstreamInjectStrategy() *UpstreamInjectStrategy
NewUpstreamInjectStrategy creates a new UpstreamInjectStrategy instance.
func (*UpstreamInjectStrategy) Authenticate ¶ added in v0.14.0
func (*UpstreamInjectStrategy) Authenticate( ctx context.Context, req *http.Request, strategy *authtypes.BackendAuthStrategy, ) error
Authenticate injects the upstream IDP token from the identity into the request header.
This method:
- Skips authentication for health check requests (no user identity to inject)
- Retrieves the authenticated identity from the request context
- Looks up the upstream token for the configured provider name
- Sets the Authorization header with the upstream token as a Bearer token
Parameters:
- ctx: Request context containing the authenticated identity (or health check marker)
- req: The HTTP request to authenticate
- strategy: Backend auth strategy containing upstream inject configuration
Returns an error if:
- No identity is found in the context
- Strategy configuration is nil or missing UpstreamInject
- The upstream token for the configured provider is not found in the identity
func (*UpstreamInjectStrategy) Name ¶ added in v0.14.0
func (*UpstreamInjectStrategy) Name() string
Name returns the strategy identifier.
func (*UpstreamInjectStrategy) Validate ¶ added in v0.14.0
func (*UpstreamInjectStrategy) Validate(strategy *authtypes.BackendAuthStrategy) error
Validate checks if the required strategy configuration fields are present and valid.
This method verifies that:
- The UpstreamInject configuration block is present
- ProviderName is present and non-empty
This validation is typically called during configuration parsing to fail fast if the strategy is misconfigured.
type XAAStrategy ¶ added in v0.32.0
type XAAStrategy struct {
// contains filtered or unexported fields
}
XAAStrategy implements XAA (Cross-Application Access) as a two-step token exchange, following draft-ietf-oauth-identity-assertion-authz-grant (ID-JAG):
- Step A (RFC 8693): Exchange the user's ID token at the IdP for an ID-JAG JWT.
- Step B (RFC 7523): Exchange the ID-JAG at the target AS for an access token.
Both steps run on every Authenticate call. The upper vMCP TokenCache layer is responsible for reusing the resulting access token across requests; this strategy holds no local cache.
The subject ID token is not validated locally before Step A. The IdP enforces its own exp check; if the token is expired, Step A returns an OAuth invalid_grant error which propagates to the caller. Callers that need fine-grained re-auth signals can inspect it with:
var re *oauth2.RetrieveError
if errors.As(err, &re) && re.ErrorCode == "invalid_grant" { ... }
func NewXAAStrategy ¶ added in v0.32.0
func NewXAAStrategy(envReader env.Reader) *XAAStrategy
NewXAAStrategy creates a new XAAStrategy instance.
func (*XAAStrategy) Authenticate ¶ added in v0.32.0
func (s *XAAStrategy) Authenticate( ctx context.Context, req *http.Request, strategy *authtypes.BackendAuthStrategy, ) error
Authenticate performs the two-step XAA (ID-JAG) flow and injects the resulting access token into the backend request.
This method:
- Parses and validates the XAA configuration from the strategy
- For health check requests: uses a client credentials grant at TargetTokenURL if target client credentials are configured; otherwise skips authentication
- For regular requests: retrieves the user's ID token from the identity's UpstreamIDTokens map, performs Step A (token exchange for ID-JAG) and Step B (JWT Bearer grant for access token), then injects the access token
Parameters:
- ctx: Request context containing the authenticated identity (or health check marker)
- req: The HTTP request to authenticate
- strategy: Backend auth strategy containing XAA configuration
Returns an error if:
- Strategy configuration is invalid or incomplete
- No identity is found in the context (regular requests only)
- The upstream ID token for the configured provider is not found
- Step A (token exchange) or Step B (JWT Bearer grant) fails
func (*XAAStrategy) Name ¶ added in v0.32.0
func (*XAAStrategy) Name() string
Name returns the strategy identifier.
func (*XAAStrategy) Validate ¶ added in v0.32.0
func (s *XAAStrategy) Validate(strategy *authtypes.BackendAuthStrategy) error
Validate checks if the required configuration fields are present and valid.
This method verifies that:
- IDPTokenURL is present and a valid HTTPS (or localhost HTTP) URL with a host and no fragment
- TargetTokenURL is present and a valid HTTPS (or localhost HTTP) URL with a host and no fragment
- TargetAudience is present
- Client secrets are only provided when client IDs are present, and a configured client ID has an accompanying secret source
As a side effect, this resolves client secrets from the environment when a *ClientSecretEnv var is configured, and returns an error if that var is unset.
This validation is typically called during configuration parsing to fail fast if the strategy is misconfigured.