Documentation
¶
Overview ¶
Package authserver provides configuration and validation for the OAuth authorization server.
Package authserver provides a centralized OAuth 2.0 Authorization Server implementation using ory/fosite for issuing JWTs to clients.
The auth server supports:
- OAuth 2.0 Authorization Code flow with PKCE (RFC 7636)
- Dynamic Client Registration (RFC 7591)
- Upstream IDP delegation (authenticates users via external IdP like Google, Okta)
- JWT access tokens with configurable lifespans
- OIDC discovery (/.well-known/openid-configuration)
- OAuth 2.0 Authorization Server Metadata (/.well-known/oauth-authorization-server, RFC 8414)
Usage ¶
The primary entry point is authserver.New(), which creates an OAuth authorization server with a single handler. Storage is a required parameter:
stor := storage.NewMemoryStorage()
server, err := authserver.New(ctx, cfg, stor)
if err != nil {
return err
}
// Mount handler on your HTTP server (serves all OAuth/OIDC endpoints)
mux.Handle("/", server.Handler())
Configuration ¶
The server requires a Config struct with issuer URL, signing key configuration, upstream IDP settings, and allowed audiences. See the Config type for details.
cfg := authserver.Config{
Issuer: "https://auth.example.com",
Upstreams: []authserver.UpstreamConfig{{Config: upstreamCfg}},
AllowedAudiences: []string{"https://mcp.example.com"},
}
stor := storage.NewMemoryStorage()
server, err := authserver.New(ctx, cfg, stor)
Storage ¶
The auth server requires a storage backend for tokens, authorization codes, and client registrations. Currently available:
- In-memory storage (suitable for single-instance deployments)
Example with memory storage:
stor := storage.NewMemoryStorage() server, err := authserver.New(ctx, cfg, stor)
IDP Token Storage ¶
When using upstream IDP delegation, tokens from the external IdP are stored and can be retrieved via the IDPTokenStorage interface for use by middleware (e.g., token swap middleware that replaces JWT auth with upstream tokens).
Subpackages ¶
The authserver package is organized into subpackages:
- server: HTTP handlers and OAuth server configuration
- storage: Token and authorization storage backends
- upstream: Upstream Identity Provider communication
Index ¶
- Constants
- func CloseIdleConnections(s Server) bool
- func DefaultUpstreamFactory(ctx context.Context, cfg *UpstreamConfig) (upstream.OAuth2Provider, error)
- func JWTBearerGrantEnabled(trustedIssuers []tokenexchange.TrustedIssuer) bool
- func PreflightSPIFFEStaticClientCollisions(ctx context.Context, base storage.Storage, trust *SPIFFETrustConfig) error
- func ResolveFirstUpstreamName(names []string) string
- func ResolveUpstreamName(name string) string
- func SPIFFEPatternsOverlap(first, second string) (bool, error)
- func ValidateConfidentialClientTransport(allowConfidential, insecureAllowHTTP bool, issuer string, ...) error
- func ValidateForceConfidentialRedirectURIs(uris []string, allowConfidential bool) error
- func ValidateResourceIndicators(values []string, field string) error
- func ValidateSPIFFEBundleEndpoint(endpoint SPIFFEBundleEndpointSourceRunConfig) error
- func ValidateSPIFFEPrincipalPattern(pattern string) error
- func ValidateSPIFFETrust(trustDomains []SPIFFETrustDomainRunConfig, ...) error
- type CIMDRunConfig
- type Config
- type DCRUpstreamConfig
- type DelegateClient
- type DelegateClientRunConfig
- type DeprecatedFieldPath
- type IdentityFromTokenRunConfig
- type InboundGrantCapabilities
- type InboundGrantsRunConfig
- type JWTBearerInboundGrantRunConfig
- type JWTBearerIssuerPolicyRunConfig
- type NormalizedInboundGrants
- type OAuth2UpstreamRunConfig
- type OIDCUpstreamRunConfig
- type RunConfig
- type SPIFFEAssociationRegistry
- type SPIFFEAuthenticationMethod
- type SPIFFEAuthorizationPolicy
- type SPIFFEBundleEndpointProfile
- type SPIFFEBundleEndpointSourceRunConfig
- type SPIFFEBundleSourceConfig
- type SPIFFEBundleSourceRunConfig
- type SPIFFEBundleSourceType
- type SPIFFEClientAuthConfig
- func (c SPIFFEClientAuthConfig) AuthorizationPolicy() SPIFFEAuthorizationPolicy
- func (c SPIFFEClientAuthConfig) ClientID() string
- func (c SPIFFEClientAuthConfig) Methods() []SPIFFEAuthenticationMethod
- func (c SPIFFEClientAuthConfig) Principal() string
- func (c SPIFFEClientAuthConfig) TrustDomainRef() string
- type SPIFFEClientAuthRunConfig
- type SPIFFETrustConfig
- type SPIFFETrustDomain
- type SPIFFETrustDomainRunConfig
- type SPIFFEWorkloadAPIBundleSourceRunConfig
- type Server
- type SigningKeyRunConfig
- type TokenExchangeInboundGrantRunConfig
- type TokenExchangeIssuerPolicyRunConfig
- type TokenLifespanRunConfig
- type TokenResponseMappingRunConfig
- type UpstreamConfig
- type UpstreamProviderFactory
- type UpstreamProviderType
- type UpstreamRunConfig
- type UserInfoFieldMappingRunConfig
- type UserInfoRunConfig
Constants ¶
const ( // SPIFFEAuthenticationMethodX509 authenticates a workload with an X.509-SVID. SPIFFEAuthenticationMethodX509 SPIFFEAuthenticationMethod = "spiffe_x509" // SPIFFEAuthenticationMethodJWT authenticates a workload with a JWT-SVID. SPIFFEAuthenticationMethodJWT SPIFFEAuthenticationMethod = "spiffe_jwt" // SPIFFEGrantTypeTokenExchange is the only SPIFFE client grant supported by // this configuration surface. SPIFFEGrantTypeTokenExchange = oauthproto.GrantTypeTokenExchange // SPIFFEBundleSourceTypeEndpoint selects a HTTPS SPIFFE Bundle Endpoint. SPIFFEBundleSourceTypeEndpoint SPIFFEBundleSourceType = "bundle_endpoint" // SPIFFEBundleSourceTypeWorkloadAPI selects the local SPIFFE Workload API. SPIFFEBundleSourceTypeWorkloadAPI SPIFFEBundleSourceType = "workload_api" // SPIFFEBundleEndpointProfileHTTPSWeb authenticates the bundle endpoint's // TLS connection with a Web PKI certificate (the SPIFFE Bundle Endpoint // "https_web" profile). SPIFFEBundleEndpointProfileHTTPSWeb SPIFFEBundleEndpointProfile = "https_web" // SPIFFEBundleEndpointProfileHTTPSSPIFFE authenticates the bundle // endpoint's TLS connection with an X.509-SVID trusted by a separately // distributed root (the SPIFFE Bundle Endpoint "https_spiffe" profile). SPIFFEBundleEndpointProfileHTTPSSPIFFE SPIFFEBundleEndpointProfile = "https_spiffe" )
const CurrentSchemaVersion = "v0.1.0"
CurrentSchemaVersion is the current version of the authserver RunConfig schema.
const DefaultUpstreamName = "default"
DefaultUpstreamName is the name assigned to a single unnamed upstream.
Variables ¶
This section is empty.
Functions ¶
func CloseIdleConnections ¶ added in v0.47.0
CloseIdleConnections releases the idle keep-alive connections pooled by s's upstream IDP providers, without touching storage, and reports whether s supported the operation. Only an implementation of Server that does not come from New can report false; the production type is checked at compile time.
An embedder that reconstructs the server to change its upstream set — passing the same storage.Storage and keys.KeyProvider so token and JWKS continuity is preserved — must retire the superseded server with this function rather than Close, because Close would also close the storage the new server is now serving through. That split is the whole point: without it there is no correct call to make.
Safe to call on a server that is still serving: only idle connections are closed and in-flight requests are unaffected. See upstream.IdleConnectionCloser for the per-provider capability this delegates to, and for the caller-owned-client exemption.
Scope: upstream HTTP pools only. A server configured with TrustedIssuers also holds one JWKS refresh worker pool per issuer; those are released by Close, not by this function — draining them would stop the background key refresh a still-serving server depends on, and this function is safe to call on a live server. An embedder retiring a superseded server with this function therefore keeps its JWKS workers until the storage it shares with the replacement can be closed via Close.
func DefaultUpstreamFactory ¶ added in v0.47.0
func DefaultUpstreamFactory(ctx context.Context, cfg *UpstreamConfig) (upstream.OAuth2Provider, error)
DefaultUpstreamFactory creates the production upstream provider based on type. For OIDC providers, it creates an OIDCProviderImpl with discovery and ID token validation. For OAuth2 providers, it creates a BaseOAuth2Provider.
It is exported so a Config.UpstreamFactory implementation can delegate to the built-in behavior for the upstreams it does not want to handle itself.
func JWTBearerGrantEnabled ¶ added in v0.47.0
func JWTBearerGrantEnabled(trustedIssuers []tokenexchange.TrustedIssuer) bool
JWTBearerGrantEnabled reports whether any trusted issuer has the RFC 7523 JWT-bearer grant configured.
func PreflightSPIFFEStaticClientCollisions ¶ added in v0.47.0
func PreflightSPIFFEStaticClientCollisions(ctx context.Context, base storage.Storage, trust *SPIFFETrustConfig) error
PreflightSPIFFEStaticClientCollisions rejects static client IDs that already exist in durable storage. It runs before upstream DCR registration so a collision cannot leave an orphaned upstream registration.
func ResolveFirstUpstreamName ¶ added in v0.33.0
ResolveFirstUpstreamName returns the resolved name of the first element of names, or DefaultUpstreamName when names is empty. It is the single implementation of the "first upstream or default" pattern used wherever a subject-provider name must be derived from a list of configured upstreams.
func ResolveUpstreamName ¶ added in v0.13.0
ResolveUpstreamName returns the canonical name for an upstream. An empty name is resolved to DefaultUpstreamName ("default").
func SPIFFEPatternsOverlap ¶ added in v0.47.0
SPIFFEPatternsOverlap reports whether two principal patterns — each a concrete SPIFFE ID or a terminal /* wildcard — overlap, using the same normalization (via the go-spiffe parser) and prefix semantics as the runtime association validator. Exported so the operator CRD admission path can reject overlapping principal patterns (e.g. "/agent/*" and "/agent/one") at admission time instead of only at reconcile time.
func ValidateConfidentialClientTransport ¶ added in v0.43.0
func ValidateConfidentialClientTransport( allowConfidential, insecureAllowHTTP bool, issuer string, insecureAllowConfidentialOverLoopbackHTTP bool, ) error
ValidateConfidentialClientTransport rejects cleartext HTTP configurations when any confidential client is enabled. It delegates to the server-layer validator so direct AuthorizationServerParams construction cannot bypass the same transport policy.
func ValidateForceConfidentialRedirectURIs ¶ added in v0.43.0
ValidateForceConfidentialRedirectURIs rejects a misconfigured force_confidential_redirect_uris list: a non-empty list requires allowConfidential (there is no confidential-client path to force a registration onto otherwise), and every entry must be a valid https non-loopback redirect URI. The https-non-loopback requirement mirrors the restriction validateAuthMethod (pkg/authserver/server/registration/dcr.go) already applies to ordinary confidential DCR: a redirect URI reachable on loopback or a private scheme is by construction a public client (OAuth 2.1 §2.1), and this override must not be a way to punch through that restriction and hand a distributed native app a secret.
func ValidateResourceIndicators ¶ added in v0.47.0
ValidateResourceIndicators validates the context-independent shape of RFC 8707 resource indicators: each must be a syntactically valid absolute HTTP(S) URI with a non-empty host, no userinfo, and no fragment. It does not check allowlist membership, which needs the reconcile-time-derived allowed_audiences value (see validateSPIFFEResources and MCPExternalAuthConfig's own admission-time call for this shape-only half).
func ValidateSPIFFEBundleEndpoint ¶ added in v0.47.0
func ValidateSPIFFEBundleEndpoint(endpoint SPIFFEBundleEndpointSourceRunConfig) error
ValidateSPIFFEBundleEndpoint validates a SPIFFE Bundle Endpoint URL and its TLS-authentication profile. Exported so the operator CRD admission path can reject the same structurally invalid endpoints at admission time instead of only at reconcile time; fetching or loading a bundle from the endpoint remains a separate, later step.
func ValidateSPIFFEPrincipalPattern ¶ added in v0.47.0
ValidateSPIFFEPrincipalPattern validates a single principal pattern — a concrete SPIFFE ID or a terminal /* wildcard — using the same normalization as the runtime association validator, without comparing it to any other pattern. Exported so an admission-time caller can validate each entry in a set up front and attribute a normalization failure to the correct entry, before running SPIFFEPatternsOverlap pairwise across the set.
func ValidateSPIFFETrust ¶ added in v0.47.0
func ValidateSPIFFETrust( trustDomains []SPIFFETrustDomainRunConfig, inboundGrants *InboundGrantsRunConfig, scopesSupported []string, allowedAudiences []string, ) error
ValidateSPIFFETrust validates SPIFFE trust declarations without fetching bundles or validating credentials.
Types ¶
type CIMDRunConfig ¶ added in v0.29.0
type CIMDRunConfig struct {
// Enabled activates CIMD client lookup when true.
Enabled bool `json:"enabled" yaml:"enabled"`
// CacheMaxSize is the maximum number of CIMD documents held in the LRU cache.
// Defaults to 256 when Enabled is true and this field is zero.
CacheMaxSize int `json:"cache_max_size,omitempty" yaml:"cache_max_size,omitempty"`
// CacheFallbackTTL is the fixed TTL applied to every cached CIMD document.
// Cache-Control header parsing is not yet implemented; all entries use this value.
// Format: Go duration string (e.g. "5m", "10m", "1h").
// Defaults to 5 minutes when Enabled is true and this field is omitted.
CacheFallbackTTL string `json:"cache_fallback_ttl,omitempty" yaml:"cache_fallback_ttl,omitempty" example:"5m"`
}
CIMDRunConfig controls client_id metadata document (CIMD) support.
func (*CIMDRunConfig) Validate ¶ added in v0.29.0
func (c *CIMDRunConfig) Validate() error
Validate checks that the CIMDRunConfig fields are internally consistent.
type Config ¶
type Config struct {
// Issuer is the issuer identifier for this authorization server.
// This will be included in the "iss" claim of issued tokens.
Issuer string
// AuthorizationEndpointBaseURL overrides the base URL used for the authorization_endpoint
// in the OAuth discovery document. When empty, defaults to Issuer.
AuthorizationEndpointBaseURL string
// KeyProvider provides signing keys for JWT operations.
// Supports key rotation by returning multiple public keys for JWKS.
// If nil, an ephemeral key will be auto-generated (development only).
//
// Production: Use keys.NewFileProvider() or keys.NewProviderFromConfig()
// Testing: Use a mock or keys.NewGeneratingProvider()
KeyProvider keys.KeyProvider
// HMACSecrets contains the symmetric secrets used for signing authorization codes
// and refresh tokens (opaque tokens). Unlike the asymmetric SigningKey which
// signs JWTs for distributed verification, these secrets are used internally
// by the authorization server only.
// Current secret must be at least 32 bytes and cryptographically random.
// Must be consistent across all replicas in multi-instance deployments.
// Supports secret rotation via the Rotated field.
HMACSecrets *servercrypto.HMACSecrets
// AccessTokenLifespan is the duration that access tokens are valid.
// If zero, defaults to 1 hour.
AccessTokenLifespan time.Duration
// RefreshTokenLifespan is the duration that refresh tokens are valid.
// If zero, defaults to 7 days.
RefreshTokenLifespan time.Duration
// AuthCodeLifespan is the duration that authorization codes are valid.
// If zero, defaults to 10 minutes.
AuthCodeLifespan time.Duration
// DelegationTokenLifespan is the maximum lifetime for delegated tokens issued
// via RFC 8693 token exchange. The actual lifetime is the minimum of this value
// and the subject token's remaining lifetime. If zero, defaults to 15 minutes.
DelegationTokenLifespan time.Duration
// Upstreams contains configurations for connecting to upstream IDPs.
// At least one upstream is required - the server delegates authentication to the upstream IDP.
// Multiple upstreams form a sequential authorization chain.
Upstreams []UpstreamConfig
// UpstreamFactory, when set, is used instead of DefaultUpstreamFactory to
// construct each configured upstream's OAuth2Provider. Two reasons to set it:
//
// - Connection reuse. DefaultUpstreamFactory builds a private HTTP client
// per upstream, so a process that reconstructs the server to change its
// upstream set creates a fresh connection pool each time. A factory that
// passes a shared client via upstream.WithHTTPClient /
// upstream.WithOAuth2HTTPClient creates none. Key the sharing by
// distinct trust posture rather than by host: two upstreams can share a
// host while differing in CAFilePath, AllowPrivateIPs or
// InsecureAllowHTTP. An injected client stays owned by the caller — see
// upstream.IdleConnectionCloser — who is then responsible for its pool,
// its TLS trust and its dial-time SSRF guard.
// - Per-upstream failure isolation. Upstream construction inside New is
// otherwise all-or-nothing: one unreachable or mistyped issuer_url fails
// the whole call. A factory owning construction can apply a per-upstream
// deadline and substitute a provider for a single failing upstream while
// the rest serve.
//
// The factory cannot drop an upstream: every entry in Upstreams must yield a
// provider, and returning a nil provider with a nil error is rejected by New
// rather than producing an upstream that panics on the first authorization
// request. To serve without an upstream, omit it from Upstreams; to keep its
// slot in the chain, return a substitute provider.
//
// SECURITY: the returned provider validates the upstream's ID tokens and
// resolves user identity. A factory that returns a permissive provider
// bypasses upstream authentication for that leg of the chain. Delegate to
// DefaultUpstreamFactory for upstreams you do not need to customize.
UpstreamFactory UpstreamProviderFactory
// UpstreamFilter, when set, narrows the upstream authorization chain after the
// first leg resolves (see handlers.WithUpstreamFilter). When nil, all
// configured upstreams are walked — the current behavior. Pass nil itself,
// not a nil-valued concrete pointer implementing UpstreamFilter — a typed-nil
// interface value is non-nil and will still be wired in. Has no effect with
// fewer than 2 configured upstreams; Validate rejects that combination.
UpstreamFilter handlers.UpstreamFilter
// ScopesSupported lists the OAuth 2.0 scope values advertised in discovery documents.
// If nil or empty, defaults to registration.DefaultScopes (["openid", "profile", "email", "offline_access"]).
// This is advertised in /.well-known/openid-configuration and
// /.well-known/oauth-authorization-server discovery endpoints.
ScopesSupported []string
// BaselineClientScopes is a baseline set of OAuth 2.0 scopes the embedded
// DCR handler unions into every newly registered client's scope set. Empty
// means current behavior is preserved (DCR registers exactly what the client
// requested, or the intersection of registration.DefaultScopes with
// ScopesSupported if the client requested none).
// All entries must also be present in ScopesSupported. When ScopesSupported
// is empty, the validation gate uses registration.DefaultScopes as the
// superset — so standard OIDC scopes (e.g. "offline_access") work without
// enumerating ScopesSupported explicitly.
BaselineClientScopes []string
// AllowedAudiences is the list of valid resource URIs that tokens can be issued for.
// Per RFC 8707, the "resource" parameter in authorization and token requests is
// validated against this list. MCP clients are required to include the resource
// parameter, so this should be configured with the canonical URIs of all MCP servers
// this authorization server issues tokens for.
//
// Security: An empty list means NO audiences are permitted (secure default).
// When empty, any request with a "resource" parameter will be rejected with
// "invalid_target". Configure this for proper MCP specification compliance.
AllowedAudiences []string
// CIMDEnabled enables the CIMD storage decorator so the authorization server
// accepts HTTPS URLs as client_id values without prior DCR registration.
//
// A resolved CIMD client is write-through persisted into the underlying
// storage (see CIMDStorageDecorator.fetch) so that token-endpoint session
// rehydration finds it. That row is marked DCR-issued and therefore
// expires (DefaultDCRClientTTL, currently 30 days), but disabling
// CIMDEnabled does not itself evict or invalidate any row a prior enabled
// period already persisted — GetClient is instead wrapped to refuse any
// URL-shaped client_id outright while CIMDEnabled is false (see
// decorateStorageForCIMD / storage.NewCIMDShapeGuardStorage), so such a
// row simply cannot be resolved for as long as CIMD stays disabled.
// Re-enabling CIMDEnabled before that TTL expires makes the stale
// snapshot resolvable again without a fresh document fetch, until the row
// expires or a new fetch overwrites it. Document rotation and revocation
// generally follow the same rule: an existing persisted row keeps
// authenticating from its stored snapshot, with no re-validation of
// scopes, redirect URIs, or auth method, until it is naturally re-fetched
// or its TTL lapses.
CIMDEnabled bool
// CIMDCacheMaxSize is the maximum number of CIMD documents held in the LRU
// cache. Zero is replaced by a default (256) in applyDefaults when CIMDEnabled
// is true.
CIMDCacheMaxSize int
// CIMDCacheFallbackTTL is the fixed TTL applied to all cached CIMD documents
// (Cache-Control header parsing is not yet implemented). Zero is replaced by
// a default (5 minutes) in applyDefaults when CIMDEnabled is true.
CIMDCacheFallbackTTL time.Duration
// InsecureAllowHTTP permits an http:// issuer URL for non-localhost hosts.
// Only set this for in-cluster Kubernetes deployments on a trusted network.
// Production deployments reachable outside the cluster MUST use https://.
InsecureAllowHTTP bool
// TrustedIssuers lists external OIDC issuers whose tokens are accepted as
// RFC 8693 subject tokens or RFC 7523 JWT-bearer assertions. See the
// identically named field on RunConfig for the full doc comment, including
// the fail-closed AllowedActors semantics and the audience/scope constraints
// operators must account for.
TrustedIssuers []tokenexchange.TrustedIssuer
// AllowConfidentialClientRegistration permits DCR of confidential clients
// (client_secret_basic / client_secret_post). See RunConfig for the full
// semantics; disabling it does not revoke already-minted secrets.
AllowConfidentialClientRegistration bool
// AllowPrivateKeyJWTRegistration permits DCR of clients using
// private_key_jwt authentication. See RunConfig for the full semantics.
AllowPrivateKeyJWTRegistration bool
// ForceConfidentialRedirectURIs lists redirect URIs that are always
// registered as confidential clients, even when the DCR request declares
// "none". See the identically named field on RunConfig for the full
// semantics and rationale.
ForceConfidentialRedirectURIs []string
// InsecureAllowConfidentialOverLoopbackHTTP opts in to confidential clients
// when Issuer is a plain-HTTP loopback URL. See the identically named field
// on RunConfig for the full semantics and rationale.
InsecureAllowConfidentialOverLoopbackHTTP bool
// DelegateClients are pre-provisioned confidential OAuth clients in their
// resolved runtime form. ClientSecret has already been read from its file
// or environment-variable reference. See RunConfig.DelegateClients for the
// serialized configuration.
DelegateClients []DelegateClient
// DisableTokenExchange prevents registration and advertisement of the RFC
// 8693 grant. The zero value preserves the released behavior. It is set only
// when canonical inbound_grants explicitly omits token_exchange.
DisableTokenExchange bool
// SPIFFETrust is the validated, immutable runtime SPIFFE trust model. It
// must be constructed with NewSPIFFETrustConfig; a nil value means no
// SPIFFE associations are configured. The serialized declarations live on
// RunConfig and are converted at the RunConfig-to-Config boundary.
SPIFFETrust *SPIFFETrustConfig
}
Config is the pure configuration for the OAuth authorization server. All values must be fully resolved (no file paths, no env vars). This is the interface that consumers should use to configure the server.
type DCRUpstreamConfig ¶ added in v0.26.1
type DCRUpstreamConfig struct {
// DiscoveryURL is the exact RFC 8414 / OIDC Discovery document URL to
// fetch at runtime. The resolver issues a single GET against this URL
// (no well-known-path fallback) and reads registration_endpoint,
// authorization_endpoint, token_endpoint,
// token_endpoint_auth_methods_supported, and scopes_supported from the
// response. Per RFC 8414 §3.3, the document's "issuer" field must
// exactly match the upstream issuer configured on the parent
// run-config.
//
// Use this field when the upstream publishes discovery metadata at a
// path that differs from the issuer-derived well-known paths — for
// example a multi-tenant IdP whose metadata lives at
// https://idp.example.com/tenants/acme/.well-known/openid-configuration.
//
// Mutually exclusive with RegistrationEndpoint.
DiscoveryURL string `json:"discovery_url,omitempty" yaml:"discovery_url,omitempty"`
// RegistrationEndpoint is the RFC 7591 registration endpoint URL used
// directly, bypassing discovery. Because no discovery is performed,
// server-capability fields (token_endpoint_auth_methods_supported,
// scopes_supported) are unavailable on this code path; the caller is
// expected to also supply AuthorizationEndpoint, TokenEndpoint, and an
// explicit Scopes list on the parent OAuth2UpstreamRunConfig. Auth
// method falls back to the resolver's default (client_secret_basic).
//
// Mutually exclusive with DiscoveryURL.
RegistrationEndpoint string `json:"registration_endpoint,omitempty" yaml:"registration_endpoint,omitempty"`
// InitialAccessTokenFile is the path to a file containing the RFC 7591
// initial access token presented to the registration endpoint. Mutually
// exclusive with InitialAccessTokenEnvVar. Both may be omitted for open
// registration endpoints.
//nolint:lll // field tags require full JSON+YAML names
InitialAccessTokenFile string `json:"initial_access_token_file,omitempty" yaml:"initial_access_token_file,omitempty"`
// InitialAccessTokenEnvVar is the name of an environment variable
// containing the RFC 7591 initial access token. Mutually exclusive with
// InitialAccessTokenFile.
//nolint:lll // field tags require full JSON+YAML names
InitialAccessTokenEnvVar string `json:"initial_access_token_env_var,omitempty" yaml:"initial_access_token_env_var,omitempty"`
// SoftwareID is the RFC 7591 "software_id" registration metadata value,
// identifying the client software independent of any particular
// registration instance.
SoftwareID string `json:"software_id,omitempty" yaml:"software_id,omitempty"`
// SoftwareStatement is the RFC 7591 "software_statement" JWT asserting
// metadata about the client software, signed by a party the authorization
// server trusts.
SoftwareStatement string `json:"software_statement,omitempty" yaml:"software_statement,omitempty"`
}
DCRUpstreamConfig configures RFC 7591 Dynamic Client Registration for an upstream authorization server. When present on an OAuth2 upstream, the authserver performs registration at runtime to obtain client credentials, replacing the need to pre-provision a ClientID.
Exactly one of DiscoveryURL or RegistrationEndpoint must be set. DiscoveryURL points at RFC 8414 / OIDC Discovery metadata from which the registration endpoint is resolved; RegistrationEndpoint is used directly when the upstream does not publish discovery metadata.
Trust assumption: DiscoveryURL and RegistrationEndpoint are operator-supplied URLs validated only for HTTPS-or-loopback. The DCR resolver will issue outbound HTTP requests — possibly carrying the RFC 7591 initial access token as a bearer header — to whatever address those URLs resolve to. There is currently no allowlist or RFC1918 / link-local / cloud-metadata-service guard, because the operator role is fully trusted today. If the trust boundary ever changes (e.g. a multi-tenant operator deployment, or a less- privileged role gains write access to this struct via a CRD or YAML surface), this field becomes a confused-deputy SSRF vector. Hardening is tracked in https://github.com/stacklok/toolhive/issues/5135.
func (*DCRUpstreamConfig) Validate ¶ added in v0.26.1
func (c *DCRUpstreamConfig) Validate() error
Validate checks that the DCRUpstreamConfig specifies exactly one of DiscoveryURL or RegistrationEndpoint, that the configured URL is well-formed and uses HTTPS (or http on a loopback host for local development), and that the two initial-access-token sources (InitialAccessTokenFile and InitialAccessTokenEnvVar) are not both set.
DiscoveryURL triggers runtime resolution of the registration endpoint via RFC 8414 / OIDC Discovery; RegistrationEndpoint bypasses discovery for providers that do not publish metadata. Requiring exactly one prevents ambiguity about which URL the authserver should contact for registration.
URL well-formedness and HTTPS are enforced here at the schema-validation boundary so misconfiguration fails fast at startup rather than at first DCR attempt; the runtime callers (pkg/oauthproto/discovery.go and pkg/oauthproto/dcr.go) defend in depth, but this is the natural fail-fast point.
Rejecting a config that supplies both an InitialAccessTokenFile and an InitialAccessTokenEnvVar prevents a credential-rotation footgun: if both were accepted, an operator updating the env-var value would not realize the file source still wins (or vice versa) and would silently keep presenting a stale token at registration.
type DelegateClient ¶ added in v0.43.0
type DelegateClient struct {
// ClientID is the OAuth client_id this client presents at the token endpoint.
ClientID string
// ClientSecret is the resolved (plaintext) client secret.
ClientSecret string //nolint:gosec // G117: field legitimately holds sensitive data
// Scopes are the OAuth scopes this client may request.
Scopes []string
// Audiences are the RFC 8707 resource values this client may request a token for.
Audiences []string
}
DelegateClient is the resolved form of DelegateClientRunConfig: the secret has already been read from its file or environment variable reference.
type DelegateClientRunConfig ¶ added in v0.43.0
type DelegateClientRunConfig struct {
// ClientID is the OAuth client_id this client presents at the token endpoint.
ClientID string `json:"client_id" yaml:"client_id"`
// ClientSecretFile is the path to a file containing the client secret.
// If both this and ClientSecretEnvVar are set, the file takes precedence.
ClientSecretFile string `json:"client_secret_file,omitempty" yaml:"client_secret_file,omitempty"`
// ClientSecretEnvVar is the name of an environment variable containing
// the client secret. One of ClientSecretFile or ClientSecretEnvVar is
// required.
//nolint:lll // field tags require full JSON+YAML names
ClientSecretEnvVar string `json:"client_secret_env_var,omitempty" yaml:"client_secret_env_var,omitempty"`
// Scopes are the OAuth scopes this client may request. Required, and
// must be a subset of RunConfig.ScopesSupported: a declared client must
// not receive every supported scope just because this was left empty.
Scopes []string `json:"scopes" yaml:"scopes"`
// Audiences are the RFC 8707 resource values this client may request a
// token for. Required, and must be a subset of RunConfig.AllowedAudiences:
// a declared client must not receive every allowed audience just because
// this was left empty.
Audiences []string `json:"audiences" yaml:"audiences"`
}
DelegateClientRunConfig declares a pre-provisioned confidential OAuth client for authorization-server startup, so it can act as the client in an RFC 8693 token-exchange request. The secret is always a reference (file or environment variable), never an inline literal. The grant type is fixed to RFC 8693 token exchange internally and is not configurable.
type DeprecatedFieldPath ¶ added in v0.47.0
DeprecatedFieldPath identifies a populated legacy field and its canonical replacement.
type IdentityFromTokenRunConfig ¶ added in v0.28.0
type IdentityFromTokenRunConfig struct {
// SubjectPath is the dot-notation path to the subject (user ID) field.
// Required when IdentityFromToken is set.
SubjectPath string `json:"subject_path" yaml:"subject_path"`
// NamePath is the dot-notation path to the display name field.
NamePath string `json:"name_path,omitempty" yaml:"name_path,omitempty"`
// EmailPath is the dot-notation path to the email address field.
EmailPath string `json:"email_path,omitempty" yaml:"email_path,omitempty"`
}
IdentityFromTokenRunConfig configures extracting user identity claims directly from the token-endpoint response body. Mirrors the CRD type (cmd/thv-operator/api/v1beta1.IdentityFromTokenConfig) — the authoritative trust-model and uniqueness documentation lives there.
type InboundGrantCapabilities ¶ added in v0.47.0
InboundGrantCapabilities reports the effective grant families after normalization.
type InboundGrantsRunConfig ¶ added in v0.47.0
type InboundGrantsRunConfig struct {
// SPIFFEClientAuth associates SPIFFE principal patterns with explicit OAuth
// client identities and permissions. See SPIFFEClientAuthRunConfig.
SPIFFEClientAuth []SPIFFEClientAuthRunConfig `json:"spiffe_client_auth,omitempty" yaml:"spiffe_client_auth,omitempty"`
// TokenExchange configures RFC 8693 inbound clients and issuer policies.
TokenExchange *TokenExchangeInboundGrantRunConfig `json:"token_exchange,omitempty" yaml:"token_exchange,omitempty"`
// JWTBearer configures RFC 7523 issuer policies.
JWTBearer *JWTBearerInboundGrantRunConfig `json:"jwt_bearer,omitempty" yaml:"jwt_bearer,omitempty"`
}
InboundGrantsRunConfig declares canonical inbound grant configuration for separately declared trust roots. SPIFFE client authentication entries live here, alongside other inbound grant purposes, so SPIFFE is not a parallel trust path, and so client authentication and grant-family enablement (token exchange, JWT-bearer) remain independently configurable.
type JWTBearerInboundGrantRunConfig ¶ added in v0.47.0
type JWTBearerInboundGrantRunConfig struct {
IssuerPolicies []JWTBearerIssuerPolicyRunConfig `json:"issuer_policies,omitempty" yaml:"issuer_policies,omitempty"`
}
JWTBearerInboundGrantRunConfig configures RFC 7523 issuer policies.
type JWTBearerIssuerPolicyRunConfig ¶ added in v0.47.0
type JWTBearerIssuerPolicyRunConfig struct {
IssuerRef string `json:"issuer_ref" yaml:"issuer_ref"`
MaxAssertionAge string `json:"max_assertion_age" yaml:"max_assertion_age"`
SubjectBindings []tx.JWTBearerSubjectBinding `json:"subject_bindings" yaml:"subject_bindings"`
AcceptedAudiences []string `json:"accepted_audiences,omitempty" yaml:"accepted_audiences,omitempty"`
}
JWTBearerIssuerPolicyRunConfig binds RFC 7523 policy to a trusted issuer declaration.
type NormalizedInboundGrants ¶ added in v0.47.0
type NormalizedInboundGrants struct {
DelegateClients []DelegateClientRunConfig
TrustedIssuers []tx.TrustedIssuer
Capabilities InboundGrantCapabilities
DeprecatedFields []DeprecatedFieldPath
}
NormalizedInboundGrants contains copied effective inputs consumed by existing runtime validators and registration.
func NormalizeInboundGrants ¶ added in v0.47.0
func NormalizeInboundGrants(cfg *RunConfig) (*NormalizedInboundGrants, error)
NormalizeInboundGrants converts legacy and canonical declarations to the existing effective runtime structures. It never mutates cfg or any nested caller-owned slice.
type OAuth2UpstreamRunConfig ¶ added in v0.9.0
type OAuth2UpstreamRunConfig struct {
// AuthorizationEndpoint is the URL for the OAuth authorization endpoint.
AuthorizationEndpoint string `json:"authorization_endpoint" yaml:"authorization_endpoint"`
// TokenEndpoint is the URL for the OAuth token endpoint.
TokenEndpoint string `json:"token_endpoint" yaml:"token_endpoint"`
// ClientID is the OAuth 2.0 client identifier registered with the upstream IDP.
// Mutually exclusive with DCRConfig: when DCRConfig is set, ClientID is obtained
// at runtime via RFC 7591 Dynamic Client Registration and must be left empty.
ClientID string `json:"client_id" yaml:"client_id"`
// ClientSecretFile is the path to a file containing the OAuth 2.0 client secret.
// Mutually exclusive with ClientSecretEnvVar. Optional for public clients using PKCE.
ClientSecretFile string `json:"client_secret_file,omitempty" yaml:"client_secret_file,omitempty"`
// ClientSecretEnvVar is the name of an environment variable containing the client secret.
// Mutually exclusive with ClientSecretFile. Optional for public clients using PKCE.
ClientSecretEnvVar string `json:"client_secret_env_var,omitempty" yaml:"client_secret_env_var,omitempty"`
// RedirectURI is the callback URL where the upstream IDP will redirect after authentication.
// When not specified, defaults to `{issuer}/oauth/callback`.
RedirectURI string `json:"redirect_uri,omitempty" yaml:"redirect_uri,omitempty"`
// Scopes are the OAuth scopes to request from the upstream IDP.
Scopes []string `json:"scopes,omitempty" yaml:"scopes,omitempty"`
// UserInfo contains configuration for fetching user information.
// Optional: when nil, the upstream OAuth2 provider derives a deterministic
// subject by SHA-256-hashing the access token (with a "tk-" prefix) instead
// of calling a userinfo endpoint. OIDC providers always derive Subject from
// the ID token and are unaffected.
UserInfo *UserInfoRunConfig `json:"userinfo,omitempty" yaml:"userinfo,omitempty"`
// TokenResponseMapping configures custom field extraction from non-standard token responses.
// When set, the token exchange bypasses golang.org/x/oauth2 and extracts fields using
// the configured dot-notation paths.
//nolint:lll // field tags require full JSON+YAML names
TokenResponseMapping *TokenResponseMappingRunConfig `json:"token_response_mapping,omitempty" yaml:"token_response_mapping,omitempty"`
// IdentityFromToken extracts user identity (subject, name, email) directly from the
// OAuth2 token-endpoint response body using gjson dot-notation paths. When set, the
// embedded auth server skips the userinfo HTTP call entirely. Mirrors the CRD type
// (cmd/thv-operator/api/v1beta1.IdentityFromTokenConfig) — the authoritative
// trust-model and uniqueness documentation lives there.
//nolint:lll // field tags require full JSON+YAML names
IdentityFromToken *IdentityFromTokenRunConfig `json:"identity_from_token,omitempty" yaml:"identity_from_token,omitempty"`
// AdditionalAuthorizationParams are extra query parameters to include in
// authorization requests. Useful for provider-specific parameters like
// Google's access_type=offline.
//nolint:lll // field tags require full JSON+YAML names
AdditionalAuthorizationParams map[string]string `json:"additional_authorization_params,omitempty" yaml:"additional_authorization_params,omitempty"`
// DCRConfig enables RFC 7591 Dynamic Client Registration against the
// upstream authorization server. When set, the client credentials are
// obtained at runtime rather than being pre-provisioned via ClientID /
// ClientSecretFile / ClientSecretEnvVar, and ClientID must be left empty.
// Mutually exclusive with ClientID.
DCRConfig *DCRUpstreamConfig `json:"dcr_config,omitempty" yaml:"dcr_config,omitempty"`
// CAFilePath is the path to a PEM CA bundle added to the system roots.
CAFilePath string `json:"ca_file_path,omitempty" yaml:"ca_file_path,omitempty"`
// AllowPrivateIPs permits the upstream provider's HTTP client to connect to
// private IP ranges (RFC-1918, link-local). When DCRConfig is set, this
// also gates the DCR discovery and registration calls made on this
// upstream's behalf (see pkg/authserver/runner/dcr_adapter.go), so a
// single flag covers the whole upstream rather than needing a separate
// DCR-specific setting. Use only when the upstream is hosted inside the
// same cluster and has no public endpoint. HTTP-scheme restrictions are
// unchanged — HTTPS is still required for non-localhost hosts. Defaults
// to false.
AllowPrivateIPs bool `json:"allow_private_ips,omitempty" yaml:"allow_private_ips,omitempty"`
// InsecureAllowHTTP permits plain-HTTP authorization and token endpoint URLs
// for this upstream. Only for in-cluster development environments (e.g. an
// OAuth2 provider served over HTTP in a kind cluster) where TLS is not
// available. Never set this in production.
//nolint:lll // field tags require full JSON+YAML names
InsecureAllowHTTP bool `json:"insecure_allow_http,omitempty" yaml:"insecure_allow_http,omitempty"`
}
OAuth2UpstreamRunConfig contains configuration for pure OAuth 2.0 providers. OAuth 2.0 providers require explicit endpoint configuration.
func (*OAuth2UpstreamRunConfig) Validate ¶ added in v0.26.1
func (c *OAuth2UpstreamRunConfig) Validate() error
Validate checks that the OAuth2UpstreamRunConfig is internally consistent. It enforces the mutual exclusivity of ClientID and DCRConfig: exactly one must be set. A ClientID is required for pre-provisioned clients; a DCRConfig is required when client credentials are obtained at runtime via RFC 7591 Dynamic Client Registration. When DCRConfig is present, its own validity is also checked via DCRUpstreamConfig.Validate.
Validate intentionally does not verify fields handled by the shared CommonOAuthConfig or upstream.OAuth2Config validators — it only covers the run-config surface area unique to OAuth2UpstreamRunConfig.
Called from buildPureOAuth2Config at the RunConfig → upstream.OAuth2Config conversion boundary so that DCR-specific fields are validated before they are dropped during conversion.
type OIDCUpstreamRunConfig ¶ added in v0.9.0
type OIDCUpstreamRunConfig struct {
// IssuerURL is the OIDC issuer URL for automatic endpoint discovery.
// Must be a valid HTTPS URL.
IssuerURL string `json:"issuer_url" yaml:"issuer_url"`
// ClientID is the OAuth 2.0 client identifier registered with the upstream IDP.
ClientID string `json:"client_id" yaml:"client_id"`
// ClientSecretFile is the path to a file containing the OAuth 2.0 client secret.
// Mutually exclusive with ClientSecretEnvVar. Optional for public clients using PKCE.
ClientSecretFile string `json:"client_secret_file,omitempty" yaml:"client_secret_file,omitempty"`
// ClientSecretEnvVar is the name of an environment variable containing the client secret.
// Mutually exclusive with ClientSecretFile. Optional for public clients using PKCE.
ClientSecretEnvVar string `json:"client_secret_env_var,omitempty" yaml:"client_secret_env_var,omitempty"`
// RedirectURI is the callback URL where the upstream IDP will redirect after authentication.
// When not specified, defaults to `{issuer}/oauth/callback`.
RedirectURI string `json:"redirect_uri,omitempty" yaml:"redirect_uri,omitempty"`
// Scopes are the OAuth scopes to request from the upstream IDP.
// If not specified, defaults to ["openid", "offline_access"].
// When using AdditionalAuthorizationParams with provider-specific refresh
// token mechanisms (e.g., Google's access_type=offline), set explicit scopes
// to avoid sending both offline_access and the provider-specific parameter.
Scopes []string `json:"scopes,omitempty" yaml:"scopes,omitempty"`
// UserInfoOverride allows customizing UserInfo fetching behavior for OIDC providers.
// By default, the UserInfo endpoint is discovered automatically via OIDC discovery.
UserInfoOverride *UserInfoRunConfig `json:"userinfo_override,omitempty" yaml:"userinfo_override,omitempty"`
// AdditionalAuthorizationParams are extra query parameters to include in
// authorization requests. Useful for provider-specific parameters like
// Google's access_type=offline.
//nolint:lll // field tags require full JSON+YAML names
AdditionalAuthorizationParams map[string]string `json:"additional_authorization_params,omitempty" yaml:"additional_authorization_params,omitempty"`
// SubjectClaim names the validated ID-token claim to use as the upstream
// subject. Defaults to "sub" when empty. Set for IdPs where "sub" isn't
// stable per user (e.g. Entra/Azure AD's "oid"). See upstream.OIDCConfig.
SubjectClaim string `json:"subject_claim,omitempty" yaml:"subject_claim,omitempty"`
// CAFilePath is the path to a PEM CA bundle added to the system roots.
CAFilePath string `json:"ca_file_path,omitempty" yaml:"ca_file_path,omitempty"`
// AllowPrivateIPs permits the OIDC discovery and token HTTP clients to
// connect to private IP ranges (RFC-1918, link-local). Use only when the
// upstream is hosted inside the same cluster and has no public endpoint.
// HTTP-scheme restrictions are unchanged — HTTPS is still required for
// non-localhost hosts. Defaults to false.
AllowPrivateIPs bool `json:"allow_private_ips,omitempty" yaml:"allow_private_ips,omitempty"`
// InsecureAllowHTTP permits a plain-HTTP issuer URL and HTTP discovery
// endpoints for this upstream. Only for in-cluster development environments
// (e.g. Dex served over HTTP in a kind cluster) where TLS is not available.
// Never set this in production.
//nolint:lll // field tags require full JSON+YAML names
InsecureAllowHTTP bool `json:"insecure_allow_http,omitempty" yaml:"insecure_allow_http,omitempty"`
}
OIDCUpstreamRunConfig contains OIDC provider configuration. OIDC providers support automatic endpoint discovery via the issuer URL.
type RunConfig ¶ added in v0.9.0
type RunConfig struct {
// SchemaVersion is the version of the RunConfig schema.
SchemaVersion string `json:"schema_version" yaml:"schema_version"`
// Issuer is the issuer identifier for this authorization server.
// This will be included in the "iss" claim of issued tokens.
// Must be a valid HTTPS URL (or HTTP for localhost) without query, fragment, or trailing slash.
Issuer string `json:"issuer" yaml:"issuer"`
// AuthorizationEndpointBaseURL overrides the base URL used for the authorization_endpoint
// in the OAuth discovery document. When set, the discovery document will advertise
// `{authorization_endpoint_base_url}/oauth/authorize` instead of `{issuer}/oauth/authorize`.
// All other endpoints remain derived from the issuer.
//nolint:lll // field tags require full JSON+YAML names
AuthorizationEndpointBaseURL string `json:"authorization_endpoint_base_url,omitempty" yaml:"authorization_endpoint_base_url,omitempty"`
// SigningKeyConfig configures the signing key provider for JWT operations.
// If nil or empty, an ephemeral signing key will be auto-generated (development only).
SigningKeyConfig *SigningKeyRunConfig `json:"signing_key_config,omitempty" yaml:"signing_key_config,omitempty"`
// HMACSecretFiles contains file paths to HMAC secrets for signing authorization codes
// and refresh tokens (opaque tokens).
// First file is the current secret (must be at least 32 bytes), subsequent files
// are for rotation/verification of existing tokens.
// If empty, an ephemeral secret will be auto-generated (development only).
HMACSecretFiles []string `json:"hmac_secret_files,omitempty" yaml:"hmac_secret_files,omitempty"`
// TokenLifespans configures the duration that various tokens are valid.
// If nil, defaults are applied (access: 1h, refresh: 7d, authCode: 10m).
TokenLifespans *TokenLifespanRunConfig `json:"token_lifespans,omitempty" yaml:"token_lifespans,omitempty"`
// DelegationTokenLifespan is the maximum lifetime for delegated tokens issued
// via RFC 8693 token exchange. Specified as a Go duration string (e.g., "15m").
// If empty, defaults to 15 minutes.
DelegationTokenLifespan string `json:"delegation_token_lifespan,omitempty" yaml:"delegation_token_lifespan,omitempty"`
// Upstreams configures connections to upstream Identity Providers for
// interactive authorization. It may be empty only when DelegateClients or a
// TrustedIssuer with JWTBearerGrant enables token-only operation.
// Multiple upstreams are supported for sequential authorization chains.
Upstreams []UpstreamRunConfig `json:"upstreams" yaml:"upstreams"`
// ScopesSupported lists the OAuth 2.0 scope values advertised in discovery documents.
// If empty, defaults to registration.DefaultScopes (["openid", "profile", "email", "offline_access"]).
ScopesSupported []string `json:"scopes_supported,omitempty" yaml:"scopes_supported,omitempty"`
// BaselineClientScopes is a baseline set of OAuth 2.0 scopes unioned into every
// DCR registration. All values must appear in ScopesSupported; the auth server
// rejects this RunConfig at startup otherwise. Empty means current behavior is
// preserved (registered scope = client-requested, or the intersection of
// DefaultScopes with ScopesSupported if the client requested none).
// When ScopesSupported is empty, the subset check uses registration.DefaultScopes
// (the same set applyDefaults would substitute at startup) — so
// BaselineClientScopes containing standard OIDC scopes works without enumerating
// ScopesSupported explicitly.
//nolint:lll // field tags require full JSON+YAML names
BaselineClientScopes []string `json:"baseline_client_scopes,omitempty" yaml:"baseline_client_scopes,omitempty"`
// AllowedAudiences is the list of valid resource URIs that tokens can be issued for.
// Per RFC 8707, the "resource" parameter in authorization and token requests is
// validated against this list. Required for MCP compliance.
AllowedAudiences []string `json:"allowed_audiences" yaml:"allowed_audiences"`
// 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 instead of
// injecting upstream IdP tokens the proxy strips the client's credential headers
// (Authorization, Cookie, Proxy-Authorization) after the JWT is validated — the
// backend receives an unauthenticated request. Incompatible with token exchange
// and AWS STS, which would re-add credentials after the strip.
//nolint:lll // field tags require full JSON+YAML names
DisableUpstreamTokenInjection bool `json:"disable_upstream_token_injection,omitempty" yaml:"disable_upstream_token_injection,omitempty"`
// CIMD controls client_id metadata document support. When enabled, the
// embedded authorization server accepts HTTPS URLs as client_id values
// and resolves them via the CIMD protocol instead of requiring DCR.
CIMD *CIMDRunConfig `json:"cimd,omitempty" yaml:"cimd,omitempty"`
// InsecureAllowHTTP permits an http:// issuer URL for non-localhost hosts.
// Only set this for in-cluster Kubernetes deployments on a trusted network.
// Production deployments reachable outside the cluster MUST use https://.
//nolint:lll // field tags require full JSON+YAML names
InsecureAllowHTTP bool `json:"insecure_allow_http,omitempty" yaml:"insecure_allow_http,omitempty"`
// TrustedIssuers lists external OIDC trust declarations.
//
// This legacy field is deprecated; RFC 8693 and JWT-bearer policies embedded in these entries
// remain supported for compatibility. New configurations should put policy
// under InboundGrants and reference a named trusted issuer.
//
// See tokenexchange.TrustedIssuer for the per-issuer field reference, and
// docs/arch/17-token-exchange-delegation.md for the trust model, consent
// signals, and operator-facing constraints (audience/scope bounding,
// subject namespace qualification, required client binding) that aren't
// visible from the config shape alone.
//nolint:lll // field tags require full JSON+YAML names
TrustedIssuers []tokenexchange.TrustedIssuer `json:"trusted_issuers,omitempty" yaml:"trusted_issuers,omitempty"`
// AllowConfidentialClientRegistration permits Dynamic Client Registration
// of confidential clients: when true, /oauth/register accepts
// token_endpoint_auth_method values client_secret_basic and
// client_secret_post in addition to "none" (still the default on
// omission) and mints a client_secret returned exactly once. Confidential
// clients are restricted to https non-loopback redirect URIs, and
// registrations idle for more than DefaultDCRClientTTL (30 days) are
// evicted and must re-register. This gates registration only: disabling
// it does not revoke or reject already-minted secrets at the token
// endpoint.
//
// Security: /oauth/register is unauthenticated, so this issues client
// secrets to any caller. Combining it with InsecureAllowHTTP is rejected
// by Validate.
//nolint:lll // field tags require full JSON+YAML names
AllowConfidentialClientRegistration bool `json:"allow_confidential_client_registration,omitempty" yaml:"allow_confidential_client_registration,omitempty"`
// AllowPrivateKeyJWTRegistration permits Dynamic Client Registration of
// clients using private_key_jwt authentication. This is independent of
// AllowConfidentialClientRegistration and defaults to false. Registration
// behavior is controlled independently by the DCR handler and discovery
// metadata.
//
// Security: /oauth/register is unauthenticated. Unlike
// AllowConfidentialClientRegistration, this is NOT rejected when combined
// with InsecureAllowHTTP: registration never returns a secret for a
// private_key_jwt client, so there is nothing for cleartext HTTP to
// expose.
//nolint:lll // field tags require full JSON+YAML names
AllowPrivateKeyJWTRegistration bool `json:"allow_private_key_jwt_registration,omitempty" yaml:"allow_private_key_jwt_registration,omitempty"`
// ForceConfidentialRedirectURIs lists redirect URIs that must be registered
// as confidential clients regardless of the token_endpoint_auth_method the
// DCR request declares. A registration whose redirect_uris contains an
// EXACT match for one of these entries is issued a real client_secret and
// reported back as token_endpoint_auth_method "client_secret_post", even
// if the request said "none" or omitted the field.
//
// This exists for MCP clients (Perplexity is the known case) that declare
// themselves public (token_endpoint_auth_method: "none") per RFC 7591 but
// then refuse to proceed because the response carries no client_secret —
// a self-contradictory request no conformant server can satisfy as
// written. RFC 7591 §3.2.1 permits the server to substitute metadata, so
// this takes such a client at its word that it wants a secret.
//
// Exact matching is deliberate: it is not a way to obtain a usable
// credential for another client. An attacker who registers with someone
// else's callback URI is issued a secret for a client whose authorization
// codes are delivered to that someone else's redirect endpoint, not to
// the attacker — the secret is useless without also controlling the
// callback.
//
// Requires AllowConfidentialClientRegistration; every entry must be a
// valid https non-loopback URI (Validate rejects loopback entries — the
// same restriction AllowConfidentialClientRegistration itself enforces
// exists so secrets do not land in distributed native apps, and this
// override must not bypass it). Remove an entry once the client is fixed
// to handle "none" registrations correctly.
//nolint:lll // field tags require full JSON+YAML names
ForceConfidentialRedirectURIs []string `json:"force_confidential_redirect_uris,omitempty" yaml:"force_confidential_redirect_uris,omitempty"`
// InsecureAllowConfidentialOverLoopbackHTTP opts in to confidential clients
// when Issuer is a plain-HTTP loopback URL. Without this flag, that
// combination is rejected: a loopback http:// issuer is normally fine for
// local development (the traffic never leaves the machine), but client
// secrets would otherwise travel over cleartext. Defaults to false. Has no
// effect when there are no confidential clients or Issuer is https.
//
// Applies identically to delegate clients and DCR-registered clients. The
// Kubernetes CRD requires the explicit opt-in for a delegate client with an
// HTTP issuer; the shared transport validator enforces that its host is
// loopback — see EmbeddedAuthServerConfig's doc comment.
//
// private_key_jwt registration has no equivalent flag or transport
// restriction: unlike confidential registration, it never returns a
// client_secret (or any other secret) in the DCR response, so there is
// nothing here for cleartext HTTP to expose.
//nolint:lll // field tags require full JSON+YAML names
InsecureAllowConfidentialOverLoopbackHTTP bool `` /* 127-byte string literal not displayed */
// DelegateClients declares confidential OAuth clients to register at
// authorization-server startup, including clients intended for RFC 8693
// token exchange.
//
// This legacy field is deprecated; use InboundGrants.TokenExchange.DelegateClients.
//
// Independent of AllowConfidentialClientRegistration: declaring a client
// here does not require or enable self-service confidential DCR, and
// setting that flag does not declare or enable any client here. They
// govern different endpoints — this field is static configuration the
// operator controls directly, while the flag is admission policy for the
// unauthenticated /oauth/register endpoint.
//
// See DelegateClientRunConfig for the per-client field reference.
DelegateClients []DelegateClientRunConfig `json:"delegate_clients,omitempty" yaml:"delegate_clients,omitempty"`
// SPIFFETrustDomains declares SPIFFE trust roots. Each declaration must be
// referenced by an InboundGrants.SPIFFEClientAuth entry.
SPIFFETrustDomains []SPIFFETrustDomainRunConfig `json:"spiffe_trust_domains,omitempty" yaml:"spiffe_trust_domains,omitempty"`
// InboundGrants declares canonical inbound grant configuration, including
// SPIFFE client authentication, delegate clients, and issuer policy. A
// non-nil value explicitly controls grant-family enablement.
InboundGrants *InboundGrantsRunConfig `json:"inbound_grants,omitempty" yaml:"inbound_grants,omitempty"`
}
RunConfig is the serializable configuration for the embedded auth server. It contains no secrets - only file paths and environment variable names that will be resolved at runtime.
This follows the same pattern as pkg/runner.RunConfig - it's serializable, versioned, and portable. Secrets are referenced by file path or environment variable name, never embedded directly.
func (*RunConfig) Validate ¶ added in v0.27.2
Validate checks that the on-disk RunConfig is internally consistent. Called by the runner before resolving secrets and building the runtime Config; it catches operator-supplied misconfiguration early so server startup fails loudly instead of degrading silently at runtime.
type SPIFFEAssociationRegistry ¶ added in v0.47.0
type SPIFFEAssociationRegistry struct {
// contains filtered or unexported fields
}
SPIFFEAssociationRegistry is the immutable runtime index of validated SPIFFE associations. It selects policy only; it neither accepts nor authenticates a SPIFFE credential.
func NewSPIFFEAssociationRegistry ¶ added in v0.47.0
func NewSPIFFEAssociationRegistry(trust *SPIFFETrustConfig) (*SPIFFEAssociationRegistry, error)
NewSPIFFEAssociationRegistry creates an immutable lookup registry from a trust configuration. A nil trust configuration represents an absent SPIFFE configuration and returns nil without enabling SPIFFE clients.
type SPIFFEAuthenticationMethod ¶ added in v0.47.0
type SPIFFEAuthenticationMethod string
SPIFFEAuthenticationMethod identifies the credential type permitted for a SPIFFE workload. Methods are explicit so introducing another credential type cannot silently broaden a policy.
type SPIFFEAuthorizationPolicy ¶ added in v0.47.0
type SPIFFEAuthorizationPolicy struct {
// contains filtered or unexported fields
}
SPIFFEAuthorizationPolicy is the immutable authorization policy selected by a validated SPIFFE association.
func (SPIFFEAuthorizationPolicy) Audiences ¶ added in v0.47.0
func (p SPIFFEAuthorizationPolicy) Audiences() []string
Audiences returns a copy of the permitted RFC 8693 token audiences.
func (SPIFFEAuthorizationPolicy) GrantTypes ¶ added in v0.47.0
func (p SPIFFEAuthorizationPolicy) GrantTypes() []string
GrantTypes returns a copy of the permitted OAuth grant types.
func (SPIFFEAuthorizationPolicy) Resources ¶ added in v0.47.0
func (p SPIFFEAuthorizationPolicy) Resources() []string
Resources returns a copy of the permitted RFC 8707 resource indicators.
func (SPIFFEAuthorizationPolicy) Scopes ¶ added in v0.47.0
func (p SPIFFEAuthorizationPolicy) Scopes() []string
Scopes returns a copy of the permitted OAuth scopes.
type SPIFFEBundleEndpointProfile ¶ added in v0.47.0
type SPIFFEBundleEndpointProfile string
SPIFFEBundleEndpointProfile identifies how a SPIFFE Bundle Endpoint's TLS connection is authenticated, per the SPIFFE Federation specification.
type SPIFFEBundleEndpointSourceRunConfig ¶ added in v0.47.0
type SPIFFEBundleEndpointSourceRunConfig struct {
URL string `json:"url" yaml:"url"`
// Profile selects how the endpoint's TLS connection is authenticated:
// SPIFFEBundleEndpointProfileHTTPSWeb (Web PKI) or
// SPIFFEBundleEndpointProfileHTTPSSPIFFE (a separately distributed
// X.509-SVID root). Required, since the future bundle loader cannot
// otherwise know which trust anchor to use for the initial connection.
Profile SPIFFEBundleEndpointProfile `json:"profile" yaml:"profile"`
}
SPIFFEBundleEndpointSourceRunConfig declares a HTTPS SPIFFE Bundle Endpoint.
type SPIFFEBundleSourceConfig ¶ added in v0.47.0
type SPIFFEBundleSourceConfig struct {
// contains filtered or unexported fields
}
SPIFFEBundleSourceConfig is the normalized bundle-source discriminator.
func (SPIFFEBundleSourceConfig) Endpoint ¶ added in v0.47.0
func (c SPIFFEBundleSourceConfig) Endpoint() string
Endpoint returns the configured Bundle Endpoint URL, or an empty string for a Workload API source.
func (SPIFFEBundleSourceConfig) Profile ¶ added in v0.47.0
func (c SPIFFEBundleSourceConfig) Profile() SPIFFEBundleEndpointProfile
Profile returns the configured Bundle Endpoint authentication profile, or an empty string for a Workload API source.
func (SPIFFEBundleSourceConfig) Type ¶ added in v0.47.0
func (c SPIFFEBundleSourceConfig) Type() SPIFFEBundleSourceType
Type returns the selected bundle-source type.
type SPIFFEBundleSourceRunConfig ¶ added in v0.47.0
type SPIFFEBundleSourceRunConfig struct {
Type SPIFFEBundleSourceType `json:"type" yaml:"type"`
Endpoint *SPIFFEBundleEndpointSourceRunConfig `json:"endpoint,omitempty" yaml:"endpoint,omitempty"`
WorkloadAPI *SPIFFEWorkloadAPIBundleSourceRunConfig `json:"workload_api,omitempty" yaml:"workload_api,omitempty"`
}
SPIFFEBundleSourceRunConfig is a discriminated bundle-source declaration. Type determines which, and only which, source payload may be set.
type SPIFFEBundleSourceType ¶ added in v0.47.0
type SPIFFEBundleSourceType string
SPIFFEBundleSourceType identifies the selected trust-bundle source.
type SPIFFEClientAuthConfig ¶ added in v0.47.0
type SPIFFEClientAuthConfig struct {
// contains filtered or unexported fields
}
SPIFFEClientAuthConfig is an immutable normalized association and policy.
func (SPIFFEClientAuthConfig) AuthorizationPolicy ¶ added in v0.47.0
func (c SPIFFEClientAuthConfig) AuthorizationPolicy() SPIFFEAuthorizationPolicy
AuthorizationPolicy returns a defensive copy of the association policy.
func (SPIFFEClientAuthConfig) ClientID ¶ added in v0.47.0
func (c SPIFFEClientAuthConfig) ClientID() string
ClientID returns the configured OAuth client ID.
func (SPIFFEClientAuthConfig) Methods ¶ added in v0.47.0
func (c SPIFFEClientAuthConfig) Methods() []SPIFFEAuthenticationMethod
Methods returns a copy of permitted authentication methods.
func (SPIFFEClientAuthConfig) Principal ¶ added in v0.47.0
func (c SPIFFEClientAuthConfig) Principal() string
Principal returns the canonical SPIFFE ID or terminal wildcard policy pattern.
func (SPIFFEClientAuthConfig) TrustDomainRef ¶ added in v0.47.0
func (c SPIFFEClientAuthConfig) TrustDomainRef() string
TrustDomainRef returns the configured trust-domain declaration name.
type SPIFFEClientAuthRunConfig ¶ added in v0.47.0
type SPIFFEClientAuthRunConfig struct {
// TrustDomainRef identifies the SPIFFE trust-domain declaration governing
// this association policy.
TrustDomainRef string `json:"trust_domain_ref" yaml:"trust_domain_ref"`
// PrincipalPattern is a concrete SPIFFE ID or a terminal /* pattern within
// the declared trust domain.
PrincipalPattern string `json:"principal_pattern" yaml:"principal_pattern"`
// ClientID is the explicit OAuth client_id. It is never derived from a
// SPIFFE ID.
ClientID string `json:"client_id" yaml:"client_id"`
Methods []SPIFFEAuthenticationMethod `json:"methods" yaml:"methods"`
// Resources are RFC 8707 resource indicators this association may
// request. Must be a subset of the server's allowed_audiences allowlist
// (RunConfig.AllowedAudiences) — the same RFC 8707 resource-URI list
// DelegateClientRunConfig.Audiences is validated against. Distinct from
// Audiences: a resource permission does not imply the same value is also
// a permitted token audience, or vice versa.
Resources []string `json:"resources,omitempty" yaml:"resources,omitempty"`
// Audiences are RFC 8693 token audiences this association may request.
// This is an independent request dimension from Resources: it is not
// bounded by allowed_audiences (which is an RFC 8707 resource-URI list)
// and may contain non-URI logical audience identifiers.
Audiences []string `json:"audiences" yaml:"audiences"`
// Scopes are OAuth scopes granted to this association. They must be a
// subset of the server's effective supported scopes.
Scopes []string `json:"scopes" yaml:"scopes"`
// GrantTypes are the OAuth grant types this association may use. Client
// authentication does not by itself confer any grant.
GrantTypes []string `json:"grant_types" yaml:"grant_types"`
}
SPIFFEClientAuthRunConfig associates one SPIFFE principal pattern from a declared trust domain with an explicit OAuth client identity and permissions.
type SPIFFETrustConfig ¶ added in v0.47.0
type SPIFFETrustConfig struct {
// contains filtered or unexported fields
}
SPIFFETrustConfig is the immutable normalized SPIFFE trust model used at runtime. Its zero value is valid and denotes no SPIFFE trust domains or associations configured — external packages may safely construct SPIFFETrustConfig{} directly.
func NewSPIFFETrustConfig ¶ added in v0.47.0
func NewSPIFFETrustConfig( trustDomains []SPIFFETrustDomainRunConfig, inboundGrants *InboundGrantsRunConfig, scopesSupported []string, allowedAudiences []string, ) (*SPIFFETrustConfig, error)
NewSPIFFETrustConfig validates and normalizes SPIFFE trust declarations into an immutable runtime model. It does not load trust bundles or authenticate credentials. The zero value SPIFFETrustConfig{} is also valid and denotes no SPIFFE trust domains or associations configured — the same value this constructor returns for empty input — so callers do not need to avoid constructing it directly.
func (*SPIFFETrustConfig) Associations ¶ added in v0.47.0
func (c *SPIFFETrustConfig) Associations() []SPIFFEClientAuthConfig
Associations returns a defensive copy of the normalized association policies.
func (*SPIFFETrustConfig) TrustDomain ¶ added in v0.47.0
func (c *SPIFFETrustConfig) TrustDomain(name string) (SPIFFETrustDomain, bool)
TrustDomain returns the normalized trust-domain record declared under name, and whether a declaration by that name exists.
type SPIFFETrustDomain ¶ added in v0.47.0
type SPIFFETrustDomain struct {
// contains filtered or unexported fields
}
SPIFFETrustDomain is the immutable normalized form of a declared SPIFFE trust domain: its canonical trust domain string, enabled credential methods, and bundle-source declaration. Future X.509/JWT-SVID validators look this up by declaration name instead of re-parsing the raw RunConfig, so the canonical trust domain and enabled methods have exactly one authoritative source.
func (SPIFFETrustDomain) BundleSource ¶ added in v0.47.0
func (d SPIFFETrustDomain) BundleSource() SPIFFEBundleSourceConfig
BundleSource returns the selected, immutable bundle-source declaration.
func (SPIFFETrustDomain) Methods ¶ added in v0.47.0
func (d SPIFFETrustDomain) Methods() []SPIFFEAuthenticationMethod
Methods returns a copy of the credential methods this trust domain enables.
func (SPIFFETrustDomain) TrustDomain ¶ added in v0.47.0
func (d SPIFFETrustDomain) TrustDomain() string
TrustDomain returns the canonical SPIFFE trust domain string.
type SPIFFETrustDomainRunConfig ¶ added in v0.47.0
type SPIFFETrustDomainRunConfig struct {
// Name uniquely identifies this declaration and is referenced by
// InboundGrants.SPIFFEClientAuth entries.
Name string `json:"name" yaml:"name"`
// TrustDomain is the SPIFFE trust domain accepted by this declaration.
TrustDomain string `json:"trust_domain" yaml:"trust_domain"`
// Methods explicitly enables the supported credential types for this trust
// domain. No authentication method is enabled when the list is empty.
Methods []SPIFFEAuthenticationMethod `json:"methods" yaml:"methods"`
// BundleSource declares exactly one future trust-bundle source. It is
// validated for shape only; fetching or loading a bundle from it is a
// later step.
BundleSource SPIFFEBundleSourceRunConfig `json:"bundle_source" yaml:"bundle_source"`
}
SPIFFETrustDomainRunConfig declares one SPIFFE trust domain. Credential authentication is deliberately outside this configuration step.
type SPIFFEWorkloadAPIBundleSourceRunConfig ¶ added in v0.47.0
type SPIFFEWorkloadAPIBundleSourceRunConfig struct{}
SPIFFEWorkloadAPIBundleSourceRunConfig selects the local SPIFFE Workload API. It deliberately has no payload; loading and deployment details are deferred to the bundle-loading implementation.
type Server ¶ added in v0.9.0
type Server interface {
// Handler returns an http.Handler that serves all OAuth/OIDC endpoints:
// - /.well-known/openid-configuration (OIDC Discovery)
// - /.well-known/oauth-authorization-server (RFC 8414 OAuth AS Metadata)
// - /.well-known/jwks.json (JSON Web Key Set)
// - /oauth/authorize (Authorization endpoint)
// - /oauth/token (Token endpoint)
// - /oauth/callback (Upstream IDP callback)
// - /oauth/register (Dynamic Client Registration, RFC 7591)
//
// The handler uses internal routing - the consumer doesn't need to know
// about the endpoint structure.
Handler() http.Handler
// IDPTokenStorage returns storage for upstream IDP tokens.
// Returns nil if no upstream IDP is configured.
IDPTokenStorage() storage.UpstreamTokenStorage
// UpstreamTokenRefresher returns a refresher that can refresh expired upstream
// tokens using the upstream provider's refresh token grant.
// Returns nil if no upstream IDP is configured.
UpstreamTokenRefresher() storage.UpstreamTokenRefresher
// DCRStore returns the persistent DCR credential store the server is wired
// against. This is the same DCRCredentialStore used by the upstream-DCR
// resolver at boot, so callers can read RFC 7591 client registrations
// without bypassing the storage backend the server itself reads from.
//
// SECURITY: the returned interface surfaces raw `client_secret` and
// `registration_access_token` values. Callers MUST NOT log or render the
// returned values; treat the handle the same way you would treat a
// secrets manager client. Intended for admin / diagnostic code paths and
// integration tests, not for general consumers.
//
// Lifecycle: the returned handle's lifetime is bound to Server.Close —
// methods invoked after Close have backend-specific behavior (a
// MemoryStorage continues to serve reads; a RedisStorage will error on
// its closed connection pool).
DCRStore() storage.DCRCredentialStore
// Close releases resources held by the server. It drains the upstream idle
// connections (see the CloseIdleConnections function) and then closes
// storage. Do not call it on a server whose storage is shared with another
// live server; retire that one with CloseIdleConnections instead.
Close() error
}
Server is the OAuth authorization server. It provides HTTP handlers that serve all OAuth/OIDC endpoints.
type SigningKeyRunConfig ¶ added in v0.9.0
type SigningKeyRunConfig struct {
// KeyDir is the directory containing PEM-encoded private key files.
// All key filenames are relative to this directory.
// In Kubernetes, this is typically a mounted Secret volume.
KeyDir string `json:"key_dir,omitempty" yaml:"key_dir,omitempty"`
// SigningKeyFile is the filename of the primary signing key (relative to KeyDir).
// This key is used for signing new tokens.
SigningKeyFile string `json:"signing_key_file,omitempty" yaml:"signing_key_file,omitempty"`
// FallbackKeyFiles are filenames of additional keys for verification (relative to KeyDir).
// These keys are included in the JWKS endpoint for token verification but are NOT
// used for signing new tokens. Useful for key rotation.
FallbackKeyFiles []string `json:"fallback_key_files,omitempty" yaml:"fallback_key_files,omitempty"`
}
SigningKeyRunConfig configures where to load signing keys from. Keys are loaded from PEM-encoded files on disk (typically mounted from secrets).
type TokenExchangeInboundGrantRunConfig ¶ added in v0.47.0
type TokenExchangeInboundGrantRunConfig struct {
DelegateClients []DelegateClientRunConfig `json:"delegate_clients,omitempty" yaml:"delegate_clients,omitempty"`
IssuerPolicies []TokenExchangeIssuerPolicyRunConfig `json:"issuer_policies,omitempty" yaml:"issuer_policies,omitempty"`
}
TokenExchangeInboundGrantRunConfig configures RFC 8693 inbound clients and issuer policies.
type TokenExchangeIssuerPolicyRunConfig ¶ added in v0.47.0
type TokenExchangeIssuerPolicyRunConfig struct {
IssuerRef string `json:"issuer_ref" yaml:"issuer_ref"`
ExpectedAudience string `json:"expected_audience" yaml:"expected_audience"`
ActorClaim string `json:"actor_claim,omitempty" yaml:"actor_claim,omitempty"`
AllowedActors []string `json:"allowed_actors,omitempty" yaml:"allowed_actors,omitempty"`
ActorMatcher string `json:"actor_matcher,omitempty" yaml:"actor_matcher,omitempty"`
AllowedDelegateClients []string `json:"allowed_delegate_clients" yaml:"allowed_delegate_clients"`
AllowMayAct bool `json:"allow_may_act,omitempty" yaml:"allow_may_act,omitempty"`
}
TokenExchangeIssuerPolicyRunConfig binds RFC 8693 policy to a trusted issuer declaration.
type TokenLifespanRunConfig ¶ added in v0.9.0
type TokenLifespanRunConfig struct {
// AccessTokenLifespan is the duration that access tokens are valid.
// If empty, defaults to 1 hour.
AccessTokenLifespan string `json:"access_token_lifespan,omitempty" yaml:"access_token_lifespan,omitempty"`
// RefreshTokenLifespan is the duration that refresh tokens are valid.
// If empty, defaults to 7 days (168h).
RefreshTokenLifespan string `json:"refresh_token_lifespan,omitempty" yaml:"refresh_token_lifespan,omitempty"`
// AuthCodeLifespan is the duration that authorization codes are valid.
// If empty, defaults to 10 minutes.
AuthCodeLifespan string `json:"auth_code_lifespan,omitempty" yaml:"auth_code_lifespan,omitempty"`
}
TokenLifespanRunConfig holds token lifetime configuration. All durations are specified as Go duration strings (e.g., "1h", "30m", "168h").
type TokenResponseMappingRunConfig ¶ added in v0.11.2
type TokenResponseMappingRunConfig struct {
// AccessTokenPath is the dot-notation path to the access token (required).
AccessTokenPath string `json:"access_token_path" yaml:"access_token_path"`
// ScopePath is the dot-notation path to the scope. Defaults to "scope".
ScopePath string `json:"scope_path,omitempty" yaml:"scope_path,omitempty"`
// RefreshTokenPath is the dot-notation path to the refresh token. Defaults to "refresh_token".
RefreshTokenPath string `json:"refresh_token_path,omitempty" yaml:"refresh_token_path,omitempty"`
// ExpiresInPath is the dot-notation path to the expires_in value. Defaults to "expires_in".
ExpiresInPath string `json:"expires_in_path,omitempty" yaml:"expires_in_path,omitempty"`
}
TokenResponseMappingRunConfig maps non-standard token response fields to standard fields. Paths support dot-notation for nested JSON fields (e.g., "authed_user.access_token").
type UpstreamConfig ¶
type UpstreamConfig struct {
// Name uniquely identifies this upstream.
// Used for routing decisions and session binding in multi-upstream scenarios.
// If empty when only one upstream is configured, defaults to "default".
Name string `json:"name,omitempty" yaml:"name,omitempty"`
// Type specifies the provider type: "oidc" or "oauth2".
Type UpstreamProviderType `json:"type" yaml:"type"`
// OAuth2Config contains OAuth 2.0 provider configuration.
// Used when Type is "oauth2". Must be nil when Type is "oidc".
OAuth2Config *upstream.OAuth2Config `json:"oauth2_config,omitempty" yaml:"oauth2_config,omitempty"`
// OIDCConfig contains OIDC provider configuration (uses discovery).
// Used when Type is "oidc". Must be nil when Type is "oauth2".
OIDCConfig *upstream.OIDCConfig `json:"oidc_config,omitempty" yaml:"oidc_config,omitempty"`
}
UpstreamConfig wraps an upstream IDP configuration with identifying metadata. It supports both OIDC providers (with discovery) and pure OAuth 2.0 providers.
type UpstreamProviderFactory ¶ added in v0.47.0
type UpstreamProviderFactory func(ctx context.Context, cfg *UpstreamConfig) (upstream.OAuth2Provider, error)
UpstreamProviderFactory constructs the OAuth2Provider for one configured upstream IDP. Set it on Config.UpstreamFactory to own upstream construction; DefaultUpstreamFactory is the built-in implementation and can be delegated to.
type UpstreamProviderType ¶ added in v0.9.0
type UpstreamProviderType string
UpstreamProviderType identifies the type of upstream Identity Provider.
const ( // UpstreamProviderTypeOIDC is for OIDC providers with discovery support. UpstreamProviderTypeOIDC UpstreamProviderType = "oidc" // UpstreamProviderTypeOAuth2 is for pure OAuth 2.0 providers with explicit endpoints. UpstreamProviderTypeOAuth2 UpstreamProviderType = "oauth2" )
type UpstreamRunConfig ¶ added in v0.9.0
type UpstreamRunConfig struct {
// Name uniquely identifies this upstream.
// Used for routing decisions and session binding in multi-upstream scenarios.
// If empty when only one upstream is configured, defaults to "default".
Name string `json:"name,omitempty" yaml:"name,omitempty"`
// Type specifies the provider type: "oidc" or "oauth2".
Type UpstreamProviderType `json:"type" yaml:"type"`
// OIDCConfig contains OIDC-specific configuration.
// Required when Type is "oidc", must be nil when Type is "oauth2".
OIDCConfig *OIDCUpstreamRunConfig `json:"oidc_config,omitempty" yaml:"oidc_config,omitempty"`
// OAuth2Config contains OAuth 2.0-specific configuration.
// Required when Type is "oauth2", must be nil when Type is "oidc".
OAuth2Config *OAuth2UpstreamRunConfig `json:"oauth2_config,omitempty" yaml:"oauth2_config,omitempty"`
}
UpstreamRunConfig configures an upstream identity provider.
type UserInfoFieldMappingRunConfig ¶ added in v0.9.0
type UserInfoFieldMappingRunConfig struct {
// SubjectFields is an ordered list of field names to try for the user ID.
// The first non-empty value found will be used.
// Default: ["sub"]
SubjectFields []string `json:"subject_fields,omitempty" yaml:"subject_fields,omitempty"`
// NameFields is an ordered list of field names to try for the display name.
// The first non-empty value found will be used.
// Default: ["name"]
NameFields []string `json:"name_fields,omitempty" yaml:"name_fields,omitempty"`
// EmailFields is an ordered list of field names to try for the email address.
// The first non-empty value found will be used.
// Default: ["email"]
EmailFields []string `json:"email_fields,omitempty" yaml:"email_fields,omitempty"`
}
UserInfoFieldMappingRunConfig maps provider-specific field names to standard UserInfo fields. This allows adapting non-standard provider responses to the canonical UserInfo structure.
type UserInfoRunConfig ¶ added in v0.9.0
type UserInfoRunConfig struct {
// EndpointURL is the URL of the userinfo endpoint.
EndpointURL string `json:"endpoint_url" yaml:"endpoint_url"`
// HTTPMethod is the HTTP method to use for the userinfo request.
// If not specified, defaults to GET.
HTTPMethod string `json:"http_method,omitempty" yaml:"http_method,omitempty"`
// AdditionalHeaders contains extra headers to include in the userinfo request.
// Useful for providers that require specific headers (e.g., GitHub's Accept header).
AdditionalHeaders map[string]string `json:"additional_headers,omitempty" yaml:"additional_headers,omitempty"`
// FieldMapping contains custom field mapping configuration for non-standard providers.
// If nil, standard OIDC field names are used ("sub", "name", "email").
FieldMapping *UserInfoFieldMappingRunConfig `json:"field_mapping,omitempty" yaml:"field_mapping,omitempty"`
}
UserInfoRunConfig contains UserInfo endpoint configuration. This supports both standard OIDC UserInfo endpoints and custom provider-specific endpoints.
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
Package oauthparams provides shared definitions for reserved OAuth2 authorization parameters that are managed by the framework.
|
Package oauthparams provides shared definitions for reserved OAuth2 authorization parameters that are managed by the framework. |
|
Package runner provides integration between the proxy runner and the auth server.
|
Package runner provides integration between the proxy runner and the auth server. |
|
Package server provides the OAuth 2.0 authorization server implementation for ToolHive.
|
Package server provides the OAuth 2.0 authorization server implementation for ToolHive. |
|
crypto
Package crypto provides cryptographic utilities for the OAuth authorization server.
|
Package crypto provides cryptographic utilities for the OAuth authorization server. |
|
handlers
Package handlers provides HTTP handlers for the OAuth 2.0 authorization server endpoints.
|
Package handlers provides HTTP handlers for the OAuth 2.0 authorization server endpoints. |
|
keys
Package keys provides signing key management for the OAuth authorization server.
|
Package keys provides signing key management for the OAuth authorization server. |
|
keys/mocks
Package mocks is a generated GoMock package.
|
Package mocks is a generated GoMock package. |
|
registration
Package registration provides OAuth client types and utilities, including RFC 8252 compliant loopback redirect URI support for native OAuth clients.
|
Package registration provides OAuth client types and utilities, including RFC 8252 compliant loopback redirect URI support for native OAuth clients. |
|
session
Package session provides OAuth session management for the authorization server.
|
Package session provides OAuth session management for the authorization server. |
|
tokenexchange
Package tokenexchange implements RFC 8693 token exchange and RFC 7523 JWT-bearer grants for the authorization server.
|
Package tokenexchange implements RFC 8693 token exchange and RFC 7523 JWT-bearer grants for the authorization server. |
|
Package storage provides storage interfaces and implementations for the OAuth authorization server.
|
Package storage provides storage interfaces and implementations for the OAuth authorization server. |
|
mocks
Package mocks is a generated GoMock package.
|
Package mocks is a generated GoMock package. |
|
Package upstream provides types and implementations for upstream Identity Provider communication in the OAuth authorization server.
|
Package upstream provides types and implementations for upstream Identity Provider communication in the OAuth authorization server. |
|
mocks
Package mocks is a generated GoMock package.
|
Package mocks is a generated GoMock package. |