oauth

package
v0.1.10 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 1, 2026 License: Apache-2.0 Imports: 24 Imported by: 0

Documentation

Overview

Package oauth implements OAuth 2.1 proxy functionality for remote MCP server authentication.

This package provides the server-side OAuth client and proxy implementation that allows the Muster Server to authenticate with remote MCP servers on behalf of users without exposing sensitive tokens to the Muster Agent.

Architecture

The OAuth proxy follows a three-legged OAuth 2.1 Authorization Code flow:

  1. User requests a tool that requires authentication
  2. Muster Server detects 401 Unauthorized from the remote MCP server
  3. Muster Server generates an authorization URL and returns "Auth Required" challenge
  4. User authenticates via their browser with the Identity Provider
  5. Browser redirects to Muster Server's callback endpoint with authorization code
  6. Muster Server exchanges code for tokens and stores them securely
  7. User retries the original request, which now succeeds with the stored token

Components

  • TokenStore: In-memory storage for OAuth tokens, indexed by session and issuer
  • StateStore: Manages OAuth state parameters for CSRF protection
  • Client: Handles OAuth flows, code exchange, and token refresh
  • Handler: HTTP handler for the /oauth/callback endpoint
  • Manager: Coordinates OAuth flows and integrates with the aggregator

Security

## Token Storage

Tokens are stored in-memory only and are never persisted to disk. This means:

  • Tokens are lost when the Muster Server restarts
  • Users must re-authenticate after a restart
  • No encryption-at-rest is needed since tokens exist only in process memory

For persistent token storage in future versions, encryption would be required.

## Session Isolation

Each MCP connection (SSE or Streamable HTTP) receives a unique UUID-based session ID from the mcp-go library. Tokens are stored with a composite key of (SessionID, Issuer, Scope), ensuring complete isolation between users. User A cannot access User B's tokens.

For stdio transport (single-user CLI), a default session ID is used. This is acceptable since stdio is inherently single-user (one process = one user).

## TLS/HTTPS Requirements (CRITICAL)

Production deployments MUST use HTTPS for all OAuth-related endpoints:

  • Muster Server's public URL (oauth.publicUrl configuration): The OAuth callback endpoint receives authorization codes. Without HTTPS, attackers could intercept these codes and exchange them for tokens.

  • OAuth Issuer URLs: All communication with Identity Providers (metadata discovery, token exchange, token refresh) must be over HTTPS. The issuer's TLS certificate provides integrity and authenticity guarantees for OAuth metadata.

  • Remote MCP Server URLs: When MCP servers require OAuth authentication, their endpoints should use HTTPS to protect the bearer tokens in Authorization headers.

Without TLS, the following attacks become possible:

  • Authorization code interception during OAuth callback
  • Token theft via man-in-the-middle attacks
  • Metadata manipulation to redirect token exchanges to malicious endpoints
  • Bearer token theft from Authorization headers

## Rate Limiting Recommendations

The OAuth callback endpoint (/oauth/callback by default) should be protected by rate limiting at the infrastructure level (ingress controller, load balancer, or API gateway). Recommended limits:

  • Per-IP rate limit: 10-20 requests per minute
  • Global rate limit: 100-500 requests per minute (depending on expected user base)

Rate limiting protects against:

  • Denial of service attacks on the OAuth callback endpoint
  • Brute-force attempts to guess authorization codes or state parameters
  • Resource exhaustion from excessive token exchange requests

Example Kubernetes Ingress annotation (nginx):

nginx.ingress.kubernetes.io/limit-rps: "10"
nginx.ingress.kubernetes.io/limit-connections: "5"

## Logging Security

Session IDs are truncated in log output to prevent full session identifiers from appearing in logs. Only the first 8 characters are logged (e.g., "abc12345..."). Access tokens and refresh tokens are never logged.

Token refresh operations are logged at INFO level for operational monitoring, including duration metrics for performance tracking.

SSO Support

The package supports Single Sign-On (SSO) through Token Forwarding and Token Exchange. When a user authenticates with muster, the token can be forwarded to downstream servers (Token Forwarding) or exchanged for a token valid on a remote IdP (Token Exchange).

Index

Constants

View Source
const DefaultOIDCScopes = "openid profile email groups"

DefaultOIDCScopes is the default set of scopes requested for OIDC token exchange. These scopes provide identity (openid), user profile info (profile, email), and group membership (groups) for RBAC decisions.

Variables

This section is empty.

Functions

func GetExpectedIssuer

func GetExpectedIssuer(config *api.TokenExchangeConfig) string

GetExpectedIssuer returns the expected issuer URL for token validation. If ExpectedIssuer is explicitly set in the config, it is used directly. Otherwise, the issuer is derived from DexTokenEndpoint (backward compatible).

This separation is important for proxied access scenarios:

Types

type Adapter

type Adapter struct {
	// contains filtered or unexported fields
}

Adapter implements api.OAuthHandler by wrapping the OAuth Manager. This follows the service locator pattern where packages communicate through interfaces defined in the api package.

func NewAdapter

func NewAdapter(manager *Manager) *Adapter

NewAdapter creates a new OAuth API adapter wrapping the given manager.

func (*Adapter) ClearTokenByIssuer

func (a *Adapter) ClearTokenByIssuer(sessionID, issuer string)

ClearTokenByIssuer removes all tokens for a given session and issuer.

func (*Adapter) CreateAuthChallenge

func (a *Adapter) CreateAuthChallenge(ctx context.Context, sessionID, serverName, issuer, scope string) (*api.AuthChallenge, error)

CreateAuthChallenge creates an authentication challenge for a 401 response.

func (*Adapter) ExchangeTokenForRemoteCluster

func (a *Adapter) ExchangeTokenForRemoteCluster(ctx context.Context, localToken, userID string, config *api.TokenExchangeConfig) (string, error)

ExchangeTokenForRemoteCluster exchanges a local token for one valid on a remote cluster. This implements RFC 8693 Token Exchange for cross-cluster SSO scenarios.

func (*Adapter) ExchangeTokenForRemoteClusterWithClient

func (a *Adapter) ExchangeTokenForRemoteClusterWithClient(ctx context.Context, localToken, userID string, config *api.TokenExchangeConfig, httpClient *http.Client) (string, error)

ExchangeTokenForRemoteClusterWithClient exchanges a local token for one valid on a remote cluster using a custom HTTP client. This is used when the token exchange endpoint is accessed via Teleport Application Access, which requires mutual TLS authentication.

func (*Adapter) FindTokenWithIDToken

func (a *Adapter) FindTokenWithIDToken(sessionID string) *api.OAuthToken

FindTokenWithIDToken searches for any token in the session that has an ID token. This is used as a fallback when the muster issuer is not explicitly configured. Returns the first token found with an ID token, or nil if none exists.

func (*Adapter) GetCIMDHandler

func (a *Adapter) GetCIMDHandler() http.HandlerFunc

GetCIMDHandler returns the HTTP handler for serving the CIMD.

func (*Adapter) GetCIMDPath

func (a *Adapter) GetCIMDPath() string

GetCIMDPath returns the path for serving the CIMD.

func (*Adapter) GetCallbackPath

func (a *Adapter) GetCallbackPath() string

GetCallbackPath returns the configured callback path.

func (*Adapter) GetFullTokenByIssuer

func (a *Adapter) GetFullTokenByIssuer(sessionID, issuer string) *api.OAuthToken

GetFullTokenByIssuer retrieves the full token (including ID token if available) for the given session and issuer. Returns nil if no valid token exists. The IDToken field may be empty if the token was obtained without an ID token.

func (*Adapter) GetHTTPHandler

func (a *Adapter) GetHTTPHandler() http.Handler

GetHTTPHandler returns the HTTP handler for OAuth callback endpoints.

func (*Adapter) GetToken

func (a *Adapter) GetToken(sessionID, serverName string) *api.OAuthToken

GetToken retrieves a valid token for the given session and server.

func (*Adapter) GetTokenByIssuer

func (a *Adapter) GetTokenByIssuer(sessionID, issuer string) *api.OAuthToken

GetTokenByIssuer retrieves a valid token for the given session and issuer.

func (*Adapter) IsEnabled

func (a *Adapter) IsEnabled() bool

IsEnabled returns whether OAuth proxy functionality is active.

func (*Adapter) Register

func (a *Adapter) Register()

Register registers this adapter with the API layer.

func (*Adapter) RegisterServer

func (a *Adapter) RegisterServer(serverName, issuer, scope string)

RegisterServer registers OAuth configuration for a remote MCP server.

func (*Adapter) SetAuthCompletionCallback

func (a *Adapter) SetAuthCompletionCallback(callback api.AuthCompletionCallback)

SetAuthCompletionCallback sets the callback to be called after successful authentication.

func (*Adapter) ShouldServeCIMD

func (a *Adapter) ShouldServeCIMD() bool

ShouldServeCIMD returns true if muster should serve its own CIMD.

func (*Adapter) Stop

func (a *Adapter) Stop()

Stop stops the OAuth handler and cleans up resources.

func (*Adapter) StoreToken added in v0.0.231

func (a *Adapter) StoreToken(sessionID, issuer string, token *api.OAuthToken)

StoreToken persists a token for the given session and issuer. This converts the API token to a pkg/oauth token and delegates to the manager's single backing store.

type AuthCompletionCallback

type AuthCompletionCallback func(ctx context.Context, sessionID, serverName, accessToken string) error

AuthCompletionCallback is called after successful OAuth authentication.

type AuthRequiredResponse

type AuthRequiredResponse struct {
	// Status indicates this is an auth required response.
	Status string `json:"status"` // "auth_required"

	// AuthURL is the OAuth authorization URL the user should visit.
	AuthURL string `json:"auth_url"`

	// ServerName is the name of the MCP server requiring authentication.
	ServerName string `json:"server_name,omitempty"`

	// Message is a human-readable description of why auth is needed.
	Message string `json:"message,omitempty"`
}

AuthRequiredResponse represents an authentication challenge returned when a remote MCP server requires OAuth authentication. Note: This is different from pkgoauth.AuthChallenge which represents parsed WWW-Authenticate header data. This is a user-facing response.

type AuthServerConfig

type AuthServerConfig struct {
	ServerName string
	Issuer     string
	Scope      string
}

AuthServerConfig holds OAuth configuration for a specific remote MCP server.

type Client

type Client struct {
	// contains filtered or unexported fields
}

Client handles OAuth 2.1 flows for remote MCP server authentication.

func NewClient

func NewClient(clientID, publicURL, callbackPath, cimdScopes string) *Client

NewClient creates a new OAuth client with the given configuration.

func (*Client) DiscoverMetadata

func (c *Client) DiscoverMetadata(ctx context.Context, issuer string) (*pkgoauth.Metadata, error)

DiscoverMetadata fetches OAuth metadata for an issuer. This is exposed for external access to metadata discovery.

func (*Client) ExchangeCode

func (c *Client) ExchangeCode(ctx context.Context, code, codeVerifier, issuer string) (*pkgoauth.Token, error)

ExchangeCode exchanges an authorization code for tokens.

func (*Client) GenerateAuthURL

func (c *Client) GenerateAuthURL(ctx context.Context, sessionID, serverName, issuer, scope string) (string, error)

GenerateAuthURL creates an OAuth authorization URL for user authentication. Returns the URL. The code verifier is stored with the state for later retrieval.

func (*Client) GetCIMDURL

func (c *Client) GetCIMDURL() string

GetCIMDURL returns the URL where the Client ID Metadata Document is served. This is derived from the clientID which is expected to be the CIMD URL.

func (*Client) GetClientMetadata

func (c *Client) GetClientMetadata() *pkgoauth.ClientMetadata

GetClientMetadata returns the Client ID Metadata Document for this client.

func (*Client) GetRedirectURI

func (c *Client) GetRedirectURI() string

GetRedirectURI returns the full redirect URI for OAuth callbacks.

func (*Client) GetStateStore

func (c *Client) GetStateStore() *StateStore

GetStateStore returns the state store for external access.

func (*Client) GetToken

func (c *Client) GetToken(sessionID, issuer, scope string) *pkgoauth.Token

GetToken retrieves a valid token for the given session and issuer. Returns nil if no valid token exists.

func (*Client) GetTokenStore

func (c *Client) GetTokenStore() *TokenStore

GetTokenStore returns the token store for external access.

func (*Client) SetHTTPClient

func (c *Client) SetHTTPClient(httpClient *http.Client)

SetHTTPClient sets a custom HTTP client for the OAuth client. This is useful for testing.

func (*Client) Stop

func (c *Client) Stop()

Stop stops background cleanup goroutines.

func (*Client) StoreToken

func (c *Client) StoreToken(sessionID string, token *pkgoauth.Token)

StoreToken stores a token in the token store.

type ExchangeRequest

type ExchangeRequest struct {
	// Config is the token exchange configuration for the target cluster.
	// Uses the API type directly to avoid duplication (DRY principle).
	Config *api.TokenExchangeConfig

	// SubjectToken is the local token to exchange (ID token or access token).
	SubjectToken string

	// SubjectTokenType specifies whether SubjectToken is an ID token or access token.
	// Use oidc.TokenTypeIDToken or oidc.TokenTypeAccessToken.
	// Defaults to TokenTypeIDToken if not specified.
	SubjectTokenType string

	// UserID is extracted from the validated subject token's "sub" claim.
	// CRITICAL: This must come from validated JWT claims, not user input.
	// Used for cache key generation.
	UserID string
}

ExchangeRequest contains the parameters for a token exchange operation.

type ExchangeResult

type ExchangeResult struct {
	// AccessToken is the exchanged token valid on the remote cluster.
	AccessToken string

	// IssuedTokenType is the type of the issued token.
	IssuedTokenType string

	// FromCache indicates whether the token was served from cache.
	FromCache bool
}

ExchangeResult contains the result of a successful token exchange.

type Handler

type Handler struct {
	// contains filtered or unexported fields
}

Handler provides HTTP handlers for OAuth callback endpoints.

func NewHandler

func NewHandler(client *Client) *Handler

NewHandler creates a new OAuth HTTP handler.

func (*Handler) HandleCallback

func (h *Handler) HandleCallback(w http.ResponseWriter, r *http.Request)

HandleCallback handles the OAuth callback endpoint. This is called by the browser after the user authenticates with the IdP.

func (*Handler) ServeCIMD

func (h *Handler) ServeCIMD(w http.ResponseWriter, r *http.Request)

ServeCIMD handles GET requests to serve the Client ID Metadata Document (CIMD). This allows muster to self-host its own CIMD without requiring external static hosting. The CIMD is dynamically generated from the OAuth configuration.

func (*Handler) ServeHTTP

func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request)

ServeHTTP implements http.Handler for the OAuth handler.

func (*Handler) SetManager

func (h *Handler) SetManager(manager *Manager)

SetManager sets the manager reference for callback handling. This is called by the Manager after creating the Handler.

type Manager

type Manager struct {
	// contains filtered or unexported fields
}

Manager coordinates OAuth flows for remote MCP server authentication. It manages the OAuth MCP client, HTTP handlers, and integrates with the aggregator.

func NewManager

func NewManager(cfg config.OAuthMCPClientConfig) *Manager

NewManager creates a new OAuth manager with the given configuration. The cfg parameter contains the OAuth MCP client/proxy configuration for authenticating TO remote MCP servers.

func (*Manager) ClearTokenByIssuer

func (m *Manager) ClearTokenByIssuer(sessionID, issuer string)

ClearTokenByIssuer removes all tokens for a given session and issuer. This is used to clear invalid/expired tokens before requesting fresh authentication.

func (*Manager) CreateAuthChallenge

func (m *Manager) CreateAuthChallenge(ctx context.Context, sessionID, serverName, issuer, scope string) (*AuthRequiredResponse, error)

CreateAuthChallenge creates an authentication challenge for a 401 response. Returns the auth URL the user should visit and the challenge response.

func (*Manager) ExchangeTokenForRemoteCluster

func (m *Manager) ExchangeTokenForRemoteCluster(ctx context.Context, localToken, userID string, config *api.TokenExchangeConfig) (string, error)

ExchangeTokenForRemoteCluster exchanges a local token for one valid on a remote cluster. This implements RFC 8693 Token Exchange for cross-cluster SSO scenarios.

Args:

  • ctx: Context for the operation
  • localToken: The local ID token to exchange
  • userID: The user's unique identifier (from validated JWT 'sub' claim)
  • config: Token exchange configuration for the remote cluster

Returns the exchanged access token, or an error if exchange fails.

func (*Manager) ExchangeTokenForRemoteClusterWithClient

func (m *Manager) ExchangeTokenForRemoteClusterWithClient(ctx context.Context, localToken, userID string, config *api.TokenExchangeConfig, httpClient *http.Client) (string, error)

ExchangeTokenForRemoteClusterWithClient exchanges a local token for one valid on a remote cluster using a custom HTTP client. This is used when the token exchange endpoint is accessed via Teleport Application Access, which requires mutual TLS authentication.

The httpClient parameter should be configured with the appropriate TLS certificates (e.g., Teleport Machine ID certificates). If nil, uses the default HTTP client.

Args:

  • ctx: Context for the operation
  • localToken: The local ID token to exchange
  • userID: The user's unique identifier (from validated JWT 'sub' claim)
  • config: Token exchange configuration for the remote cluster
  • httpClient: Custom HTTP client with Teleport TLS certificates (or nil for default)

Returns the exchanged access token, or an error if exchange fails.

func (*Manager) GetCIMDHandler

func (m *Manager) GetCIMDHandler() http.HandlerFunc

GetCIMDHandler returns the HTTP handler for serving the CIMD.

func (*Manager) GetCIMDPath

func (m *Manager) GetCIMDPath() string

GetCIMDPath returns the path for serving the CIMD.

func (*Manager) GetCallbackPath

func (m *Manager) GetCallbackPath() string

GetCallbackPath returns the configured callback path.

func (*Manager) GetHTTPHandler

func (m *Manager) GetHTTPHandler() http.Handler

GetHTTPHandler returns the HTTP handler for OAuth endpoints.

func (*Manager) GetServerConfig

func (m *Manager) GetServerConfig(serverName string) *AuthServerConfig

GetServerConfig returns the OAuth configuration for a server.

func (*Manager) GetToken

func (m *Manager) GetToken(sessionID, serverName string) *pkgoauth.Token

GetToken retrieves a valid token for the given session and server. mcp-go handles token refresh via its transport layer, so this method simply returns the stored token without proactive refresh.

func (*Manager) GetTokenByIssuer

func (m *Manager) GetTokenByIssuer(sessionID, issuer string) *pkgoauth.Token

GetTokenByIssuer retrieves a valid token for the given session and issuer. This is used for SSO when we have the issuer from a 401 response. mcp-go handles token refresh via its transport layer, so this method simply returns the stored token without proactive refresh.

func (*Manager) GetTokenExchanger

func (m *Manager) GetTokenExchanger() *TokenExchanger

GetTokenExchanger returns the token exchanger for direct access. This is useful for cache management and monitoring.

func (*Manager) HandleCallback

func (m *Manager) HandleCallback(ctx context.Context, code, state string) error

HandleCallback processes an OAuth callback and stores the token. Note: This is a programmatic API for testing. The production flow uses Handler.HandleCallback which is the actual HTTP endpoint and handles the auth completion callback invocation.

func (*Manager) IsEnabled

func (m *Manager) IsEnabled() bool

IsEnabled returns whether OAuth proxy is enabled.

func (*Manager) RegisterServer

func (m *Manager) RegisterServer(serverName, issuer, scope string)

RegisterServer registers OAuth configuration for a remote MCP server.

func (*Manager) SetAuthCompletionCallback

func (m *Manager) SetAuthCompletionCallback(callback AuthCompletionCallback)

SetAuthCompletionCallback sets the callback to be called after successful authentication. The aggregator uses this to establish session connections after browser OAuth completes.

func (*Manager) ShouldServeCIMD

func (m *Manager) ShouldServeCIMD() bool

ShouldServeCIMD returns true if muster should serve its own CIMD.

func (*Manager) Stop

func (m *Manager) Stop()

Stop stops the OAuth manager and cleans up resources.

func (*Manager) StoreToken added in v0.0.231

func (m *Manager) StoreToken(sessionID, issuer string, token *pkgoauth.Token)

StoreToken persists a token for the given session and issuer. This is the write path used by mcp-go's transport after a successful token refresh.

type OAuthState

type OAuthState struct {
	// SessionID links the OAuth flow to the user's session.
	SessionID string `json:"session_id"`

	// ServerName is the MCP server that requires authentication.
	ServerName string `json:"server_name"`

	// Nonce is a random value for CSRF protection.
	Nonce string `json:"nonce"`

	// CreatedAt is when the state was created (for expiration).
	CreatedAt time.Time `json:"created_at"`

	// RedirectURI is where to redirect after callback processing.
	RedirectURI string `json:"redirect_uri,omitempty"`

	// Issuer is the OAuth issuer URL for token exchange.
	Issuer string `json:"issuer,omitempty"`

	// CodeVerifier is the PKCE code verifier for this flow.
	// Stored server-side only, not transmitted in the state parameter.
	CodeVerifier string `json:"-"`
}

OAuthState represents the state parameter data for OAuth flows. This is serialized and passed through the OAuth flow to link the callback to the original request. This is server-specific as it handles CSRF protection for server-side OAuth.

type RedactedToken

type RedactedToken struct {
	// contains filtered or unexported fields
}

RedactedToken wraps a sensitive token string to prevent accidental logging.

This type implements fmt.Stringer to return "[REDACTED]" instead of the actual token value, preventing accidental credential leakage in log messages, error strings, or debug output.

Usage:

token := oauth.NewRedactedToken("secret-token-value")
fmt.Println(token)        // prints: [REDACTED]
actualValue := token.Value() // returns: "secret-token-value"

func (RedactedToken) GoString

func (t RedactedToken) GoString() string

GoString implements fmt.GoStringer for %#v formatting, also returning "[REDACTED]" to prevent accidental logging.

func (RedactedToken) IsEmpty

func (t RedactedToken) IsEmpty() bool

IsEmpty returns true if the token value is empty.

func (RedactedToken) MarshalJSON

func (t RedactedToken) MarshalJSON() ([]byte, error)

MarshalJSON implements json.Marshaler, returning "[REDACTED]" to prevent accidental JSON serialization of the token value.

func (RedactedToken) MarshalText

func (t RedactedToken) MarshalText() ([]byte, error)

MarshalText implements encoding.TextMarshaler, returning "[REDACTED]" to prevent accidental serialization of the token value.

func (RedactedToken) String

func (t RedactedToken) String() string

String implements fmt.Stringer, returning "[REDACTED]" to prevent accidental logging of the token value.

func (RedactedToken) Value

func (t RedactedToken) Value() string

Value returns the actual token value. Use this method only when the token needs to be sent in an HTTP header or similar authenticated request. Never log the result of this method.

type StateStore

type StateStore struct {
	// contains filtered or unexported fields
}

StateStore provides thread-safe storage for OAuth state parameters. State parameters are used to link OAuth callbacks to original requests and provide CSRF protection.

IMPORTANT: StateStore starts a background goroutine for cleanup. Callers MUST call Stop() when done to prevent goroutine leaks. Typically this is done via defer after creating the store, or in a shutdown hook for long-lived stores.

func NewStateStore

func NewStateStore() *StateStore

NewStateStore creates a new state store with default expiration.

func (*StateStore) Delete

func (ss *StateStore) Delete(nonce string)

Delete removes a state from the store.

func (*StateStore) GenerateState

func (ss *StateStore) GenerateState(sessionID, serverName, issuer, codeVerifier string) (encodedState string, err error)

GenerateState creates a new OAuth state parameter and stores it. Returns the encoded state string to include in the authorization URL. The nonce is embedded within the encoded state and used for server-side lookup.

Args:

  • sessionID: The user's session ID
  • serverName: The MCP server name requiring authentication
  • issuer: The OAuth issuer URL
  • codeVerifier: The PKCE code verifier for this flow

func (*StateStore) Stop

func (ss *StateStore) Stop()

Stop stops the background cleanup goroutine.

func (*StateStore) ValidateState

func (ss *StateStore) ValidateState(encodedState string) *OAuthState

ValidateState validates an OAuth state parameter from a callback. Returns the original state data if valid, nil if invalid or expired.

type TokenExchanger

type TokenExchanger struct {
	// contains filtered or unexported fields
}

TokenExchanger performs RFC 8693 OAuth 2.0 Token Exchange for cross-cluster SSO. It enables users authenticated to muster (Cluster A) to access MCP servers on remote clusters (Cluster B) by exchanging their local token for a token valid on the remote cluster's Identity Provider.

This is different from token forwarding (ForwardToken), which forwards muster's ID token directly. Token exchange is useful when:

  • Remote clusters have separate Dex instances
  • The remote Dex is configured with an OIDC connector pointing to muster's Dex
  • You need a token issued by the remote cluster's IdP

Thread-safe: Yes, the underlying TokenExchangeClient is thread-safe.

func NewTokenExchangerWithOptions

func NewTokenExchangerWithOptions(opts TokenExchangerOptions) *TokenExchanger

NewTokenExchangerWithOptions creates a new TokenExchanger with custom options.

func (*TokenExchanger) Cleanup

func (e *TokenExchanger) Cleanup() int

Cleanup removes expired tokens from the cache. This should be called periodically for long-running services.

func (*TokenExchanger) ClearAllCache

func (e *TokenExchanger) ClearAllCache()

ClearAllCache removes all cached tokens.

func (*TokenExchanger) ClearCache

func (e *TokenExchanger) ClearCache(tokenEndpoint, connectorID, userID string)

ClearCache removes a cached token for the given parameters. This is useful when a cached token is rejected by the remote server.

func (*TokenExchanger) Exchange

Exchange exchanges a local token for a token valid on a remote cluster. The token is cached to reduce the number of exchange requests.

Args:

  • ctx: Context for cancellation and timeouts
  • req: Exchange request parameters

Returns the exchanged token or an error if exchange fails.

func (*TokenExchanger) ExchangeWithClient

func (e *TokenExchanger) ExchangeWithClient(ctx context.Context, req *ExchangeRequest, httpClient *http.Client) (*ExchangeResult, error)

ExchangeWithClient exchanges a local token for a token valid on a remote cluster using a custom HTTP client. This is used when the token exchange endpoint is accessed via Teleport Application Access, which requires mutual TLS authentication.

The httpClient parameter should be configured with the appropriate TLS certificates (e.g., Teleport Machine ID certificates). If nil, uses the default exchanger client.

Args:

  • ctx: Context for cancellation and timeouts
  • req: Exchange request parameters
  • httpClient: Custom HTTP client with Teleport TLS certificates (or nil for default)

Returns the exchanged token or an error if exchange fails.

func (*TokenExchanger) GetCacheStats

func (e *TokenExchanger) GetCacheStats() oidc.TokenExchangeCacheStats

GetCacheStats returns statistics about the token exchange cache.

type TokenExchangerOptions

type TokenExchangerOptions struct {
	// Logger for debug/info messages (nil uses default logger).
	Logger *slog.Logger

	// AllowPrivateIP allows token endpoints to resolve to private IP addresses.
	// WARNING: Reduces SSRF protection. Only enable for internal/VPN deployments.
	AllowPrivateIP bool

	// CacheMaxEntries is the maximum number of cached tokens (0 = default: 10000).
	CacheMaxEntries int

	// HTTPClient is the HTTP client to use for token exchange requests.
	// If nil, an appropriate client is created based on AllowPrivateIP setting.
	// Use this to configure custom TLS settings (e.g., for self-signed certs).
	HTTPClient *http.Client
}

TokenExchangerOptions configures the TokenExchanger.

type TokenKey

type TokenKey struct {
	SessionID string
	Issuer    string
	Scope     string
}

TokenKey uniquely identifies a token in the store. Tokens are indexed by session ID, issuer, and scope to enable SSO. This is server-specific as it handles session-scoped token storage.

type TokenStore

type TokenStore struct {
	// contains filtered or unexported fields
}

TokenStore provides thread-safe in-memory storage for OAuth tokens. Tokens are indexed by session ID, issuer, and scope to support SSO.

IMPORTANT: TokenStore starts a background goroutine for cleanup. Callers MUST call Stop() when done to prevent goroutine leaks. Typically this is done via defer after creating the store, or in a shutdown hook for long-lived stores.

func NewTokenStore

func NewTokenStore() *TokenStore

NewTokenStore creates a new in-memory token store. It starts a background goroutine for periodic cleanup of expired tokens.

func (*TokenStore) Count

func (ts *TokenStore) Count() int

Count returns the number of tokens in the store.

func (*TokenStore) Delete

func (ts *TokenStore) Delete(key TokenKey)

Delete removes a token from the store.

func (*TokenStore) DeleteByIssuer

func (ts *TokenStore) DeleteByIssuer(sessionID, issuer string)

DeleteByIssuer removes all tokens for a given session and issuer. This is used to clear invalid/expired tokens before requesting fresh authentication.

func (*TokenStore) DeleteBySession

func (ts *TokenStore) DeleteBySession(sessionID string)

DeleteBySession removes all tokens for a given session.

func (*TokenStore) Get

func (ts *TokenStore) Get(key TokenKey) *pkgoauth.Token

Get retrieves a token from the store by key. Returns nil if the token doesn't exist or has expired.

func (*TokenStore) GetAllForSession

func (ts *TokenStore) GetAllForSession(sessionID string) map[TokenKey]*pkgoauth.Token

GetAllForSession returns all valid tokens for a session. This is useful for listing all servers a session is authenticated with.

func (*TokenStore) GetByIssuer

func (ts *TokenStore) GetByIssuer(sessionID, issuer string) *pkgoauth.Token

GetByIssuer finds a token for the given session and issuer, regardless of scope. This enables SSO when the exact scope doesn't match but the issuer does.

func (*TokenStore) GetTokenKeyByIssuer

func (ts *TokenStore) GetTokenKeyByIssuer(sessionID, issuer string) *TokenKey

GetTokenKeyByIssuer finds the token key for a given session and issuer. This is useful for linking session connections to their tokens.

func (*TokenStore) Stop

func (ts *TokenStore) Stop()

Stop stops the background cleanup goroutine.

func (*TokenStore) Store

func (ts *TokenStore) Store(key TokenKey, token *pkgoauth.Token)

Store saves a token in the store, indexed by the given key.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL