Documentation
¶
Overview ¶
Package server provides OAuth 2.1 protection for the Muster Server.
This package implements ADR 005 (OAuth Protection for Muster Server), allowing the Muster Server to act as an OAuth Resource Server. When enabled, all MCP endpoints require valid access tokens from authenticated clients.
Architecture ¶
The server package integrates with the mcp-oauth library to provide:
- OAuth 2.1 server with mandatory PKCE
- Dynamic client registration (RFC 7591)
- Client ID Metadata Documents (CIMD) per MCP 2025-11-25 spec
- Token validation middleware for protecting MCP endpoints
- Multiple provider support (Dex OIDC, Google OAuth)
- Token storage backends (in-memory, Valkey/Redis)
Integration ¶
The OAuth server wraps the existing aggregator HTTP handler, adding authentication and authorization before requests reach MCP endpoints.
┌─────────────────────────────────────────────────────────────┐ │ Muster Server │ │ │ │ [ OAuth Middleware (Resource Server) ] │ │ Validates Token from Agent │ │ │ │ │ ▼ │ │ [ Aggregator / Tool Handler ] │ │ │ │ │ ▼ │ │ [ OAuth Proxy (Client) ] │ │ Injects Token for Remote MCPs │ └─────────────────────────────────────────────────────────────┘
Usage ¶
To enable OAuth server protection, configure the aggregator with:
aggregator:
oauthServer:
enabled: true
baseUrl: "https://muster.example.com"
provider: "dex"
dex:
issuerUrl: "https://dex.example.com"
clientId: "muster-server"
clientSecret: "${DEX_CLIENT_SECRET}"
Endpoints ¶
When OAuth server is enabled, the following endpoints are exposed:
- /.well-known/oauth-authorization-server - Authorization Server Metadata (RFC 8414)
- /.well-known/oauth-protected-resource - Protected Resource Metadata (RFC 9728)
- /oauth/register - Dynamic Client Registration (RFC 7591)
- /oauth/authorize - OAuth Authorization
- /oauth/token - Token Endpoint
- /oauth/callback - OAuth Callback (from IdP)
- /oauth/revoke - Token Revocation (RFC 7009)
- /mcp - Protected MCP endpoint (requires Bearer token)
Index ¶
- Constants
- func ContextWithIDToken(ctx context.Context, idToken string) context.Context
- func GetIDToken(token *oauth2.Token) string
- func GetIDTokenFromContext(ctx context.Context) (string, bool)
- type OAuthHTTPServer
- func (s *OAuthHTTPServer) CreateMux() http.Handler
- func (s *OAuthHTTPServer) GetOAuthHandler() *oauth.Handler
- func (s *OAuthHTTPServer) GetOAuthServer() *oauth.Server
- func (s *OAuthHTTPServer) GetTokenStore() storage.TokenStore
- func (s *OAuthHTTPServer) SetOnAuthenticated(fn func(ctx context.Context, sessionID string))
- func (s *OAuthHTTPServer) Shutdown(ctx context.Context) error
- func (s *OAuthHTTPServer) ValidateTokenWithSubject(next http.Handler) http.Handler
- type UserInfo
Constants ¶
const ( // OAuthProviderDex is the Dex OIDC provider type. OAuthProviderDex = "dex" // OAuthProviderGoogle is the Google OAuth provider type. OAuthProviderGoogle = "google" // DefaultAccessTokenTTL is the configured TTL for access tokens (30 minutes). // This is intentionally set to match the Dex idTokens expiry (30m) so that // capTokenExpiry in mcp-oauth doesn't need to cap it further. If Dex's // idTokens expiry is shorter than this value, capTokenExpiry will // automatically reduce the effective TTL to match the provider's token lifetime. DefaultAccessTokenTTL = 30 * time.Minute // DefaultRefreshTokenTTL is the server-side TTL for refresh tokens. // Derived from pkgoauth.DefaultSessionDuration to keep server and CLI in sync. // Aligned with Dex's absoluteLifetime (720h = 30 days). Note: muster uses a // rolling TTL (reset on each rotation), while Dex's absoluteLifetime is // measured from original issuance and does NOT reset. DefaultRefreshTokenTTL = pkgoauth.DefaultSessionDuration // DefaultIPRateLimit is the default rate limit for requests per IP (requests/second). // In Kubernetes deployments, traffic may arrive from multiple distinct IPs or be // NATed through an ingress, so per-IP limits should be generous enough to avoid // false positives while still protecting against abuse. DefaultIPRateLimit = 50 // DefaultIPBurst is the default burst size for IP rate limiting. DefaultIPBurst = 100 // DefaultUserRateLimit is the default rate limit for authenticated users (requests/second). DefaultUserRateLimit = 100 // DefaultUserBurst is the default burst size for authenticated user rate limiting. DefaultUserBurst = 200 // DefaultMaxClientsPerIP is the default maximum number of clients per IP address. DefaultMaxClientsPerIP = 10 // DefaultSecurityEventRate bounds security-event log emission (events/second // per keyed event), keeping a malformed-token attack from flooding the audit // pipeline. Mirrors mcp-oauth's production-example default (1, 5). DefaultSecurityEventRate = 1 // DefaultSecurityEventBurst is the burst size for security-event log emission. DefaultSecurityEventBurst = 5 // DefaultReadHeaderTimeout is the default timeout for reading request headers. DefaultReadHeaderTimeout = 10 * time.Second // DefaultWriteTimeout is the default timeout for writing responses. DefaultWriteTimeout = 120 * time.Second // DefaultIdleTimeout is the default idle timeout for keepalive connections. DefaultIdleTimeout = 120 * time.Second )
Variables ¶
This section is empty.
Functions ¶
func ContextWithIDToken ¶ added in v0.1.26
ContextWithIDToken creates a context with the given OIDC ID token. This is used to pass the user's ID token for downstream authentication (e.g., to remote MCP servers).
func GetIDToken ¶
GetIDToken extracts the ID token from an OAuth2 token. OIDC providers include an id_token in the Extra data. Kubernetes OIDC authentication requires the ID token, not the access token.
Types ¶
type OAuthHTTPServer ¶
type OAuthHTTPServer struct {
// contains filtered or unexported fields
}
OAuthHTTPServer wraps an MCP HTTP handler with OAuth 2.1 authentication. It provides both OAuth server functionality (authorization, token issuance) and resource server protection (token validation middleware).
func NewOAuthHTTPServer ¶
func NewOAuthHTTPServer(cfg config.OAuthServerConfig, mcpHandler http.Handler, debug bool, opts ...oauth.ServerOption) (*OAuthHTTPServer, error)
NewOAuthHTTPServer creates a new OAuth-enabled HTTP server that wraps the provided MCP handler with authentication protection. Caller-provided mcp-oauth options (e.g. token-family lifecycle handlers) are forwarded to the underlying OAuth server.
func (*OAuthHTTPServer) CreateMux ¶
func (s *OAuthHTTPServer) CreateMux() http.Handler
CreateMux creates an HTTP mux that routes to both OAuth and MCP handlers. The MCP endpoints are protected by the OAuth ValidateToken middleware.
func (*OAuthHTTPServer) GetOAuthHandler ¶
func (s *OAuthHTTPServer) GetOAuthHandler() *oauth.Handler
GetOAuthHandler returns the OAuth handler for testing or direct access.
func (*OAuthHTTPServer) GetOAuthServer ¶
func (s *OAuthHTTPServer) GetOAuthServer() *oauth.Server
GetOAuthServer returns the underlying OAuth server for testing or direct access.
func (*OAuthHTTPServer) GetTokenStore ¶
func (s *OAuthHTTPServer) GetTokenStore() storage.TokenStore
GetTokenStore returns the token store for downstream OAuth passthrough.
func (*OAuthHTTPServer) SetOnAuthenticated ¶ added in v0.1.59
func (s *OAuthHTTPServer) SetOnAuthenticated(fn func(ctx context.Context, sessionID string))
SetOnAuthenticated registers a callback that fires on every authenticated MCP request after the session ID has been extracted. The aggregator uses this to trigger on-demand SSO connections from the HTTP middleware rather than from individual MCP operations.
func (*OAuthHTTPServer) Shutdown ¶
func (s *OAuthHTTPServer) Shutdown(ctx context.Context) error
Shutdown gracefully shuts down the server.
func (*OAuthHTTPServer) ValidateTokenWithSubject ¶ added in v0.1.44
func (s *OAuthHTTPServer) ValidateTokenWithSubject(next http.Handler) http.Handler
ValidateTokenWithSubject wraps the given handler with OAuth token validation and extracts the authenticated user's subject (sub claim) into the context. This is used for API endpoints that need to identify the user but don't need the full SSO/token-injection logic of the MCP middleware chain.