Documentation
¶
Overview ¶
Package oauth provides shared OAuth 2.1 types and utilities used by both the Muster Agent and Server.
This package contains the common OAuth functionality that is shared between the agent-side OAuth implementation (internal/agent/oauth) and the server-side OAuth implementation (internal/oauth).
Core Components ¶
- Token: OAuth token representation with expiry checking
- Metadata: OAuth/OIDC server metadata (RFC 8414)
- AuthChallenge: Parsed WWW-Authenticate header information
- PKCE: Proof Key for Code Exchange generation (RFC 7636)
- Client: OAuth client for metadata discovery and token operations
Usage ¶
Both the agent and server import this package for shared types and utilities, then wrap it with their specific storage backends and UI handling.
Agent usage (file-based storage, browser opening):
import "github.com/giantswarm/muster/pkg/oauth" challenge, err := oauth.ParseWWWAuthenticate(header) pkce, err := oauth.GeneratePKCE() // Uses golang.org/x/oauth2 under the hood
Server usage (in-memory storage, HTTP callbacks):
import "github.com/giantswarm/muster/pkg/oauth" client := oauth.NewClient(httpClient, logger) metadata, err := client.DiscoverMetadata(ctx, issuer)
Index ¶
- Constants
- func DefaultTokenDir() (string, error)
- func GeneratePKCERaw() (verifier, challenge string)
- func GenerateState() (string, error)
- func IsOAuthUnauthorizedError(err error) bool
- func NormalizeServerURL(serverURL string) string
- type AuthChallenge
- type AuthRequiredInfo
- type AuthStatusResponse
- type Client
- func (c *Client) BuildAuthorizationURL(authEndpoint, clientID, redirectURI, state, scope string, pkce *PKCEChallenge) (string, error)
- func (c *Client) ClearMetadataCache()
- func (c *Client) DiscoverMetadata(ctx context.Context, issuer string) (*Metadata, error)
- func (c *Client) ExchangeCode(ctx context.Context, ...) (*Token, error)
- type ClientMetadata
- type ClientOption
- type IDTokenClaims
- type Metadata
- type PKCEChallenge
- type ServerAuthStatus
- type SessionServerStatus
- type Token
Constants ¶
const ( // DefaultHTTPTimeout is the default timeout for HTTP requests. DefaultHTTPTimeout = 30 * time.Second // DefaultMetadataCacheTTL is the default TTL for cached OAuth metadata. DefaultMetadataCacheTTL = 30 * time.Minute )
const DefaultExpiryMargin = 30 * time.Second
DefaultExpiryMargin is the default margin when checking token expiry. This accounts for clock skew and network latency.
const DefaultSessionDuration = 30 * 24 * time.Hour
DefaultSessionDuration is the expected maximum session duration before re-authentication is required. This should match the server-side RefreshTokenTTL and is used by the CLI to estimate session expiry from the stored token's CreatedAt timestamp. Aligned with Dex's absoluteLifetime (720h = 30 days).
const DefaultTokenStorageDir = ".config/muster/tokens"
DefaultTokenStorageDir is the default directory for storing OAuth tokens, relative to the user's home directory. This follows XDG conventions. This constant is shared across all OAuth implementations for consistency.
const ( // DisplayAuthRequired is the formatted string shown in CLI prompts when servers require authentication. // This is displayed prominently in uppercase because it requires user action (running 'auth login'). // Example prompt: "muster staging [AUTH REQUIRED] > " DisplayAuthRequired = "[AUTH REQUIRED]" )
Display constants for user-facing output. These are formatted strings suitable for CLI prompts and status displays.
Variables ¶
This section is empty.
Functions ¶
func DefaultTokenDir ¶ added in v0.1.5
DefaultTokenDir returns the absolute path to the default token storage directory (~/.config/muster/tokens). It does not create the directory; callers that need it to exist should call os.MkdirAll themselves.
func GeneratePKCERaw ¶
func GeneratePKCERaw() (verifier, challenge string)
GeneratePKCERaw generates a PKCE code verifier and challenge as raw strings. This is useful when you don't need the full PKCEChallenge struct.
This implementation uses the standard golang.org/x/oauth2 library which provides RFC 7636 compliant PKCE generation.
Returns the verifier and S256 challenge. This function cannot fail as it uses the standard library's implementation.
func GenerateState ¶
GenerateState generates a random state parameter for OAuth. The state is used to prevent CSRF attacks and link the authorization response back to the original request.
Returns a base64url-encoded random string.
func IsOAuthUnauthorizedError ¶ added in v0.0.231
IsOAuthUnauthorizedError checks if an error indicates an OAuth authorization failure using mcp-go's typed error detection. Returns true for both transport.OAuthAuthorizationRequiredError (when WithHTTPOAuth is configured) and transport.ErrUnauthorized (bare 401 without OAuth handler).
func NormalizeServerURL ¶
NormalizeServerURL normalizes a server URL by stripping transport-specific path suffixes (/mcp, /sse) and trailing slashes to get the base server URL. This ensures consistent token storage and OAuth metadata discovery regardless of which endpoint path is used when connecting.
This function is shared across all OAuth implementations for consistency.
Types ¶
type AuthChallenge ¶
type AuthChallenge struct {
// Scheme is the authentication scheme (typically "Bearer" for OAuth 2.0).
Scheme string
// Realm is the protection realm (often the authorization server name or URL).
Realm string
// Issuer is the OAuth/OIDC issuer URL.
// This may be derived from the Realm if it's a URL.
Issuer string
// ResourceMetadataURL is the URL to the protected resource metadata.
// This follows RFC 9728 for OAuth 2.0 Protected Resource Metadata.
ResourceMetadataURL string
// Scope is the space-separated list of required OAuth scopes.
Scope string
// Error is the error code from the WWW-Authenticate header (if any).
Error string
// ErrorDescription is a human-readable error description (if any).
ErrorDescription string
}
AuthChallenge represents parsed information from a WWW-Authenticate header. This contains the OAuth server metadata needed to initiate the auth flow.
func ParseWWWAuthenticate ¶
func ParseWWWAuthenticate(header string) (*AuthChallenge, error)
ParseWWWAuthenticate parses a WWW-Authenticate header value. It supports the Bearer scheme with OAuth 2.0 and MCP-specific parameters.
Example headers:
Bearer realm="https://auth.example.com" Bearer realm="https://auth.example.com", scope="openid profile" Bearer realm="https://auth.example.com", resource_metadata="https://mcp.example.com/.well-known/oauth-protected-resource"
Returns an AuthChallenge with the parsed parameters, or an error if parsing fails.
func (*AuthChallenge) GetIssuer ¶
func (c *AuthChallenge) GetIssuer() string
GetIssuer returns the OAuth issuer URL. It prefers the explicit Issuer field, falls back to Realm if it's a URL.
func (*AuthChallenge) IsOAuthChallenge ¶
func (c *AuthChallenge) IsOAuthChallenge() bool
IsOAuthChallenge returns true if this represents an OAuth authentication challenge.
type AuthRequiredInfo ¶
type AuthRequiredInfo struct {
Server string `json:"server"`
Issuer string `json:"issuer"`
Scope string `json:"scope,omitempty"`
AuthTool string `json:"auth_tool"` // Always "core_auth_login" per ADR-008
}
AuthRequiredInfo contains information about a server requiring authentication. This is a simplified view used by the agent to build human-readable notifications.
Per ADR-008, AuthTool is always "core_auth_login" - callers can use this tool with the Server field as the argument to authenticate.
type AuthStatusResponse ¶
type AuthStatusResponse struct {
Servers []ServerAuthStatus `json:"servers"`
}
AuthStatusResponse is the structured response from the auth://status MCP resource. It provides the AI with complete information about which servers need authentication. This type is shared between the aggregator (producer) and agent (consumer).
type Client ¶
type Client struct {
// contains filtered or unexported fields
}
Client handles OAuth 2.1 protocol operations. It provides metadata discovery, token exchange, and token refresh.
func (*Client) BuildAuthorizationURL ¶
func (c *Client) BuildAuthorizationURL(authEndpoint, clientID, redirectURI, state, scope string, pkce *PKCEChallenge) (string, error)
BuildAuthorizationURL constructs an OAuth authorization URL.
func (*Client) ClearMetadataCache ¶
func (c *Client) ClearMetadataCache()
ClearMetadataCache clears the metadata cache. Useful for testing or when metadata needs to be refreshed immediately.
func (*Client) DiscoverMetadata ¶
DiscoverMetadata fetches OAuth metadata from the issuer's well-known endpoint. It tries RFC 8414 (/.well-known/oauth-authorization-server) first, then falls back to OpenID Connect (/.well-known/openid-configuration).
Results are cached with a TTL to reduce network requests.
type ClientMetadata ¶
type ClientMetadata struct {
ClientID string `json:"client_id"`
ClientName string `json:"client_name,omitempty"`
ClientURI string `json:"client_uri,omitempty"`
RedirectURIs []string `json:"redirect_uris"`
GrantTypes []string `json:"grant_types,omitempty"`
ResponseTypes []string `json:"response_types,omitempty"`
TokenEndpointAuthMethod string `json:"token_endpoint_auth_method,omitempty"`
Scope string `json:"scope,omitempty"`
LogoURI string `json:"logo_uri,omitempty"`
PolicyURI string `json:"policy_uri,omitempty"`
TermsOfServiceURI string `json:"tos_uri,omitempty"`
SoftwareID string `json:"software_id,omitempty"`
SoftwareVersion string `json:"software_version,omitempty"`
}
ClientMetadata represents OAuth 2.0 Client Metadata as defined in RFC 7591. Used for Client ID Metadata Documents (CIMD) in MCP OAuth.
type ClientOption ¶
type ClientOption func(*Client)
ClientOption configures the OAuth client.
func WithHTTPClient ¶
func WithHTTPClient(httpClient *http.Client) ClientOption
WithHTTPClient sets a custom HTTP client.
func WithMetadataCacheTTL ¶
func WithMetadataCacheTTL(ttl time.Duration) ClientOption
WithMetadataCacheTTL sets the metadata cache TTL.
type IDTokenClaims ¶
type IDTokenClaims struct {
// Subject is the unique user identifier (sub claim).
Subject string `json:"sub"`
// Email is the user's email address (email claim).
Email string `json:"email"`
}
IDTokenClaims holds the identity claims extracted from JWT ID tokens. This is used to display user identity information (subject, email) from OAuth authentication without requiring full JWT validation.
type Metadata ¶
type Metadata struct {
// Issuer is the authorization server's issuer identifier.
Issuer string `json:"issuer"`
// AuthorizationEndpoint is the URL of the authorization endpoint.
AuthorizationEndpoint string `json:"authorization_endpoint"`
// TokenEndpoint is the URL of the token endpoint.
TokenEndpoint string `json:"token_endpoint"`
// UserinfoEndpoint is the URL of the userinfo endpoint (OIDC).
UserinfoEndpoint string `json:"userinfo_endpoint,omitempty"`
// JwksURI is the URL of the JSON Web Key Set.
JwksURI string `json:"jwks_uri,omitempty"`
// RegistrationEndpoint is the URL for dynamic client registration.
RegistrationEndpoint string `json:"registration_endpoint,omitempty"`
// ScopesSupported lists the OAuth 2.0 scope values supported.
ScopesSupported []string `json:"scopes_supported,omitempty"`
// ResponseTypesSupported lists the response_type values supported.
ResponseTypesSupported []string `json:"response_types_supported,omitempty"`
// GrantTypesSupported lists the grant types supported.
GrantTypesSupported []string `json:"grant_types_supported,omitempty"`
// TokenEndpointAuthMethodsSupported lists the client authentication methods.
TokenEndpointAuthMethodsSupported []string `json:"token_endpoint_auth_methods_supported,omitempty"`
// CodeChallengeMethodsSupported lists the PKCE code challenge methods.
CodeChallengeMethodsSupported []string `json:"code_challenge_methods_supported,omitempty"`
}
Metadata represents OAuth 2.0 Authorization Server Metadata as defined in RFC 8414.
func (*Metadata) SupportsPKCE ¶
SupportsPKCE returns true if the server supports S256 PKCE.
type PKCEChallenge ¶
type PKCEChallenge struct {
// CodeVerifier is the cryptographically random string (32-96 bytes, base64url-encoded).
// This is kept secret and never transmitted to the authorization server.
CodeVerifier string
// CodeChallenge is the SHA256 hash of the verifier (base64url-encoded).
// This is sent in the authorization request.
CodeChallenge string
// CodeChallengeMethod is always "S256" for security (plain is not allowed in OAuth 2.1).
CodeChallengeMethod string
}
PKCEChallenge represents a PKCE (Proof Key for Code Exchange) challenge. PKCE is required for OAuth 2.1 public clients to prevent authorization code interception.
func GeneratePKCE ¶
func GeneratePKCE() (*PKCEChallenge, error)
GeneratePKCE generates a new PKCE code verifier and challenge. The code verifier is 32 random bytes (256 bits), base64url-encoded. The code challenge is the S256 (SHA256) hash of the verifier.
This implementation delegates to the standard golang.org/x/oauth2 library for RFC 7636 compliant PKCE generation.
Returns a PKCEChallenge ready for use in an authorization request.
type ServerAuthStatus ¶
type ServerAuthStatus struct {
Name string `json:"name"`
Status SessionServerStatus `json:"status"` // "connected", "auth_required", "reauth_required", "sso_pending", "disconnected", "error"
Issuer string `json:"issuer,omitempty"`
Scope string `json:"scope,omitempty"`
AuthTool string `json:"auth_tool,omitempty"` // "core_auth_login" for non-SSO servers; empty for SSO servers (per ADR-008)
Error string `json:"error,omitempty"`
// TokenForwardingEnabled indicates this server uses SSO via ID token forwarding.
// When true, muster forwards its own ID token (from muster's OAuth server protection)
// to this downstream server, rather than requiring a separate OAuth flow.
TokenForwardingEnabled bool `json:"token_forwarding_enabled,omitempty"`
// TokenExchangeEnabled indicates this server uses SSO via RFC 8693 Token Exchange.
// When true, muster exchanges its local token for one valid on the remote cluster's
// Identity Provider (e.g., Dex). This enables cross-cluster SSO when clusters have
// separate Dex instances. Token exchange takes precedence over token forwarding.
TokenExchangeEnabled bool `json:"token_exchange_enabled,omitempty"`
// SSOAttemptFailed indicates that SSO authentication was attempted but failed.
// This occurs when token forwarding is enabled but the downstream server
// rejected the forwarded token (e.g., audience mismatch, token expired).
// When true, the status will be "auth_required" and users should check
// server trust configuration.
SSOAttemptFailed bool `json:"sso_attempt_failed,omitempty"`
}
ServerAuthStatus represents the authentication status of a single MCP server. The Issuer field enables SSO detection - servers with the same issuer can share auth.
SSO in muster has two mechanisms:
- Token Forwarding: When TokenForwardingEnabled is true, muster forwards its own ID token to the downstream server (requires forwardToken: true in MCPServer config).
- Token Exchange: When TokenExchangeEnabled is true, muster exchanges its token for one valid on the remote cluster's IdP (for cross-cluster SSO).
type SessionServerStatus ¶ added in v0.1.72
type SessionServerStatus string
SessionServerStatus represents the per-user session authentication status of an MCP server. This is distinct from api.ServiceState which tracks global server lifecycle state.
const ( // SessionServerStatusConnected indicates the server is connected and operational. // Tools from this server are available for use. SessionServerStatusConnected SessionServerStatus = "connected" // SessionServerStatusAuthRequired indicates the server requires OAuth authentication. // This is an important status that requires user action: run 'muster auth login --server <name>'. // The server is reachable but needs authentication before tools become available. // // This status is more informative than a generic "Disconnected" because it tells // users exactly what action is needed to restore connectivity. SessionServerStatusAuthRequired SessionServerStatus = "auth_required" // SessionServerStatusDisconnected indicates the server is disconnected. // The connection was previously established but is no longer active. SessionServerStatusDisconnected SessionServerStatus = "disconnected" // SessionServerStatusError indicates the server encountered an error. // Check the error field for details about what went wrong. SessionServerStatusError SessionServerStatus = "error" // SessionServerStatusUnreachable indicates the server endpoint cannot be reached. // This is distinct from auth_required - unreachable means network/connectivity failure, // not an authentication issue. Users should not be prompted to authenticate // for unreachable servers. SessionServerStatusUnreachable SessionServerStatus = "unreachable" // SessionServerStatusFailed indicates a session-level failure (e.g., connection dropped, // unexpected error during communication). This is distinct from infrastructure // failures (tracked in MCPServer Phase) and auth failures (tracked in AuthStatus). SessionServerStatusFailed SessionServerStatus = "failed" // SessionServerStatusSSOPending indicates that SSO authentication is in progress for this // server. The server is SSO-enabled and muster is currently establishing the // connection via token forwarding or token exchange. This is a transient state // that will resolve to "connected" (on success) or "auth_required" with // sso_attempt_failed=true (on failure). // // Clients should NOT call core_auth_login for servers in this state -- they // should wait for the SSO process to complete. SessionServerStatusSSOPending SessionServerStatus = "sso_pending" // SessionServerStatusReauthRequired indicates the user's session has a broken // upstream token refresh chain (e.g., Dex -> GitHub returned 401). The ID token // has expired or is no longer available, so SSO connections cannot be maintained. // The user must re-authenticate via 'muster auth login' to restore SSO access. // This is distinct from auth_required (initial auth needed) -- reauth_required // means a previously working session has degraded. SessionServerStatusReauthRequired SessionServerStatus = "reauth_required" )
Session server status constants for use in ServerAuthStatus.Status field. These are the primary status values visible to users and AI assistants.
type Token ¶
type Token struct {
// AccessToken is the bearer token used for authorization.
AccessToken string `json:"access_token"`
// TokenType is typically "Bearer".
TokenType string `json:"token_type,omitempty"`
// RefreshToken is used to obtain new access tokens (optional).
RefreshToken string `json:"refresh_token,omitempty"`
// ExpiresIn is the token lifetime in seconds (from token response).
ExpiresIn int `json:"expires_in,omitempty"`
// ExpiresAt is the calculated expiration timestamp.
ExpiresAt time.Time `json:"expires_at,omitempty"`
// Scope is the granted scope(s), space-separated.
Scope string `json:"scope,omitempty"`
// Issuer is the token issuer (Identity Provider URL).
Issuer string `json:"issuer,omitempty"`
// IDToken is the OIDC ID token (if available).
IDToken string `json:"id_token,omitempty"`
}
Token represents an OAuth access token with associated metadata.
func (*Token) IsExpired ¶
IsExpired checks if the token has expired. Returns true if the token is expired or will expire within the given margin.
func (*Token) IsExpiredWithMargin ¶
IsExpiredWithMargin checks if the token has expired or will expire within the margin.
func (*Token) SetExpiresAtFromExpiresIn ¶
func (t *Token) SetExpiresAtFromExpiresIn()
SetExpiresAtFromExpiresIn calculates and sets ExpiresAt from ExpiresIn.
func (*Token) ToOAuth2Token ¶
ToOAuth2Token converts the Token to an oauth2.Token for compatibility with golang.org/x/oauth2.