Documentation
¶
Overview ¶
Package oauth provides OAuth 2.1 authentication for the MCP server.
This package implements OAuth 2.1 authentication according to the Model Context Protocol (MCP) specification dated 2025-06-18. The MCP server acts as an OAuth 2.1 Resource Server, using Google as the Authorization Server for secure authentication.
Architecture:
- MCP Server: OAuth 2.1 Resource Server (validates Google tokens)
- Google: OAuth 2.1 Authorization Server (issues tokens, handles user auth)
- MCP Client: OAuth 2.1 Client (handles OAuth flow, includes tokens in requests)
Key Features:
- Protected Resource Metadata (RFC 9728) - advertises Google as authorization server
- Bearer token validation via Google's userinfo endpoint
- Automatic token refresh with rotation (OAuth 2.1 security best practice)
- Rate limiting per IP address and per user with token bucket algorithm
- Secure token storage with optional AES-256-GCM encryption at rest
- Token expiration handling with automatic cleanup
- Token revocation endpoint (RFC 7009)
- Comprehensive audit logging for security events
- Client type enforcement (public vs confidential)
- PKCE S256 enforcement (plain method disabled for security)
- Integration with Google APIs (Gmail, Drive, Calendar, etc.)
Security Features (Production-Ready):
1. Token Encryption at Rest (AES-256-GCM):
- Tokens can be encrypted in memory using AES-256-GCM
- Authenticated encryption prevents tampering
- Configure via Security.EncryptionKey (32 bytes)
- Use GenerateEncryptionKey() or load from secure storage (KMS, Vault)
2. Refresh Token Rotation (OAuth 2.1):
- New refresh token issued on each use
- Old refresh token invalidated immediately
- Detects stolen tokens via reuse detection
- Enabled by default (disable via Security.DisableRefreshTokenRotation)
3. Comprehensive Audit Logging:
- All authentication events logged with structured logging
- Security events: failed auth, rate limits, invalid tokens, token reuse
- All sensitive data (tokens, emails) hashed before logging (SHA-256)
- Enabled by default (disable via Security.EnableAuditLogging=false)
4. Client Type Validation:
- Public clients (mobile, SPA) must use "none" auth method
- Confidential clients must use client_secret_basic or client_secret_post
- Prevents security violations (confidential client without secret)
5. PKCE Security:
- Only S256 method supported (plain method disabled per OAuth 2.1)
- 43-128 character code_verifier enforced
- Prevents authorization code interception attacks
6. Token Revocation (RFC 7009):
- Clients can revoke access and refresh tokens
- Client authentication required
- All revocations logged for audit trail
7. Cryptographically Secure Token Generation:
- All tokens generated using crypto/rand (not math/rand)
- 48-byte access and refresh tokens (384 bits of entropy)
- 32-byte client IDs and secrets
Security Considerations:
- Token Storage: Tokens can be encrypted at rest with AES-256-GCM. Enable via Security.EncryptionKey for production deployments.
- Logging: All sensitive data (tokens, emails, PII) is hashed before logging using SHA256 to prevent exposure in log files. Only use structured logging.
- Clock Skew: A 5-second grace period is applied to token expiration checks to handle time synchronization issues between systems.
- Refresh Token Protection: Tokens with valid refresh tokens are preserved even if the access token expires, allowing automatic renewal.
- Rate Limiting: Per-IP and per-user rate limiting prevents brute force attacks and DoS attempts. Configure based on your threat model.
Compliance:
- OAuth 2.1 Draft: Implements key security improvements
- RFC 6749: OAuth 2.0 Authorization Framework
- RFC 6750: Bearer Token Usage
- RFC 7009: Token Revocation
- RFC 7591: Dynamic Client Registration
- RFC 7636: PKCE (S256 only)
- RFC 8414: Authorization Server Metadata
- RFC 9728: Protected Resource Metadata
The package is designed to be used by the MCP server's HTTP and SSE transports to add OAuth protection to their endpoints.
Example usage:
// Generate encryption key for production (do this once, store securely)
encKey, _ := oauth.GenerateEncryptionKey()
// Or load from environment: oauth.EncryptionKeyFromBase64(os.Getenv("OAUTH_ENCRYPTION_KEY"))
// Create OAuth handler with full security features
handler, err := oauth.NewHandler(&oauth.Config{
Resource: "https://mcp.example.com",
SupportedScopes: []string{
"https://www.googleapis.com/auth/gmail.readonly",
// ... other Google scopes
},
GoogleAuth: oauth.GoogleAuthConfig{
ClientID: os.Getenv("GOOGLE_CLIENT_ID"),
ClientSecret: os.Getenv("GOOGLE_CLIENT_SECRET"),
},
RateLimit: oauth.RateLimitConfig{
Rate: 10,
Burst: 20,
UserRate: 100,
UserBurst: 200,
},
Security: oauth.SecurityConfig{
EncryptionKey: encKey, // Enable encryption
EnableAuditLogging: true, // Enable audit logs
DisableRefreshTokenRotation: false, // Enable rotation
AllowPublicClientRegistration: false, // Require auth
RegistrationAccessToken: "secure-token", // Registration token
RefreshTokenTTL: 90 * 24 * time.Hour, // 90 days
},
})
if err != nil {
log.Fatal(err)
}
// Protect MCP endpoints
http.Handle("/mcp", handler.ValidateGoogleToken(mcpHandler))
// Serve metadata endpoints
http.HandleFunc("/.well-known/oauth-protected-resource",
handler.ServeProtectedResourceMetadata)
http.HandleFunc("/.well-known/oauth-authorization-server",
handler.ServeAuthorizationServerMetadata)
// Token revocation endpoint (RFC 7009)
http.HandleFunc("/oauth/revoke", handler.ServeTokenRevocation)
Index ¶
- Constants
- Variables
- func ContextWithUserInfo(ctx context.Context, userInfo *providers.UserInfo) context.Context
- func InterstitialAppName(ctx context.Context) string
- func InterstitialRedirectURL(ctx context.Context) string
- func IsSilentAuthError(err error) bool
- func ParseOAuthError(errorCode, errorDescription string) error
- func UserInfoFromContext(ctx context.Context) (*providers.UserInfo, bool)
- type AuthorizationServerMetadata
- type CallbackResult
- type ClientRegistrationRequest
- type ClientRegistrationResponse
- type Config
- type Error
- type ErrorResponse
- type GoogleAuthConfig
- type Handler
- func (h *Handler) RegisterAuthorizationServerMetadataRoutes(mux *http.ServeMux)
- func (h *Handler) RegisterProtectedResourceMetadataRoutes(mux *http.ServeMux, mcpPath string)
- func (h *Handler) ServeAuthorization(w http.ResponseWriter, r *http.Request)
- func (h *Handler) ServeAuthorizationServerMetadata(w http.ResponseWriter, r *http.Request)
- func (h *Handler) ServeCallback(w http.ResponseWriter, r *http.Request)
- func (h *Handler) ServeClientRegistration(w http.ResponseWriter, r *http.Request)
- func (h *Handler) ServeOpenIDConfiguration(w http.ResponseWriter, r *http.Request)
- func (h *Handler) ServePreflightRequest(w http.ResponseWriter, r *http.Request)
- func (h *Handler) ServeProtectedResourceMetadata(w http.ResponseWriter, r *http.Request)
- func (h *Handler) ServeToken(w http.ResponseWriter, r *http.Request)
- func (h *Handler) ServeTokenIntrospection(w http.ResponseWriter, r *http.Request)
- func (h *Handler) ServeTokenRevocation(w http.ResponseWriter, r *http.Request)
- func (h *Handler) ValidateToken(next http.Handler) http.Handler
- type InstrumentationConfig
- type OAuthErrordeprecated
- type ProtectedResourceMetadata
- type RateLimitConfig
- type SecurityConfig
- type Server
- type ServerConfig
- type SilentAuthError
- type TokenResponse
Constants ¶
const ( // DefaultRefreshTokenTTL is the default time-to-live for refresh tokens (90 days) DefaultRefreshTokenTTL = 90 * 24 * time.Hour // DefaultAuthorizationCodeTTL is how long authorization codes are valid (10 minutes) DefaultAuthorizationCodeTTL = 10 * time.Minute // DefaultAccessTokenTTL is the default access token expiry (1 hour) DefaultAccessTokenTTL = 1 * time.Hour // DefaultCleanupInterval is how often to cleanup expired tokens (1 minute) DefaultCleanupInterval = 1 * time.Minute // DefaultRateLimitCleanupInterval is how often to cleanup inactive rate limiters DefaultRateLimitCleanupInterval = 5 * time.Minute // InactiveLimiterCleanupWindow is the time after which inactive limiters are removed InactiveLimiterCleanupWindow = 10 * time.Minute // TokenRefreshThreshold is how soon before expiry to attempt token refresh TokenRefreshThreshold = 5 * time.Minute // TokenExpiringThreshold is the minimum time before a token is considered expiring TokenExpiringThreshold = 60 // seconds // ClockSkewGrace is the grace period (in seconds) for clock skew when validating token expiration // // Security Rationale: // - Prevents false expiration errors due to minor time differences between systems // - Balances security (minimize token lifetime extension) with usability // - 5 seconds is a conservative value that handles typical NTP drift // // Trade-offs: // - Allows tokens to be used up to 5 seconds beyond their true expiration // - This is acceptable for most use cases and improves reliability // - For high-security scenarios, consider reducing or removing this grace period ClockSkewGrace = 5 // seconds )
OAuth token and code timeouts
const ( // DefaultMaxClientsPerIP is the default limit for client registrations per IP DefaultMaxClientsPerIP = 10 // DefaultRateLimitRate is the default requests per second per IP DefaultRateLimitRate = 10 // DefaultRateLimitBurst is the default burst size for rate limiting DefaultRateLimitBurst = 20 // DefaultTokenEndpointAuthMethod is the default client authentication method DefaultTokenEndpointAuthMethod = "client_secret_basic" )
OAuth client and security defaults
const ( // MinCodeVerifierLength is the minimum length for PKCE code_verifier (RFC 7636) MinCodeVerifierLength = 43 // MaxCodeVerifierLength is the maximum length for PKCE code_verifier (RFC 7636) MaxCodeVerifierLength = 128 // ClientIDTokenLength is the length of generated client IDs ClientIDTokenLength = 32 // ClientSecretTokenLength is the length of generated client secrets ClientSecretTokenLength = 48 // AccessTokenLength is the length of generated access tokens AccessTokenLength = 48 // RefreshTokenLength is the length of generated refresh tokens RefreshTokenLength = 48 // StateTokenLength is the length of generated state parameters StateTokenLength = 32 // MinStateLength is the minimum length for state parameters to prevent // timing attacks and ensure sufficient entropy for CSRF protection. // OAuth 2.1 recommends at least 128 bits (16 bytes) of entropy. // 24 characters provides 144 bits of entropy in base64, exceeding the 128-bit minimum. // This value is used as the default for server.Config.MinStateLength. MinStateLength = 24 )
PKCE and token generation constants
const ( // ClientTypeConfidential represents a confidential OAuth client ClientTypeConfidential = "confidential" // ClientTypePublic represents a public OAuth client ClientTypePublic = "public" )
OAuth client types
const ( // TokenEndpointAuthMethodNone represents no authentication (public clients) TokenEndpointAuthMethodNone = "none" // TokenEndpointAuthMethodBasic represents HTTP Basic authentication TokenEndpointAuthMethodBasic = "client_secret_basic" // TokenEndpointAuthMethodPost represents POST form parameters TokenEndpointAuthMethodPost = "client_secret_post" )
Token endpoint authentication methods (RFC 7591)
const ( // PKCEMethodS256 is the SHA256 code challenge method (recommended, OAuth 2.1) PKCEMethodS256 = "S256" // PKCEMethodPlain is the plain code challenge method (deprecated, insecure) PKCEMethodPlain = "plain" )
PKCE code challenge methods
const ( // SchemeHTTP is the HTTP URI scheme SchemeHTTP = "http" // SchemeHTTPS is the HTTPS URI scheme SchemeHTTPS = "https" )
URI schemes
const ( // MetadataPathProtectedResource is the RFC 9728 Protected Resource Metadata discovery path MetadataPathProtectedResource = "/.well-known/oauth-protected-resource" // MetadataPathAuthorizationServer is the RFC 8414 Authorization Server Metadata discovery path MetadataPathAuthorizationServer = "/.well-known/oauth-authorization-server" // MaxMetadataPathLength is the maximum allowed length for custom metadata paths // This prevents DoS attacks through excessively long path registration MaxMetadataPathLength = 256 )
OAuth discovery paths (RFC 8414, RFC 9728)
const ( // MaxLoginHintLength is the maximum length for the login_hint parameter. // This is typically an email address (RFC 5321 limits to 254 chars). // We use 256 to accommodate edge cases and remain consistent with other ID limits. MaxLoginHintLength = 256 // MaxIDTokenHintLength is the maximum length for the id_token_hint parameter. // JWTs can be large (especially with many claims), so we allow up to 64KB. // This matches maxSubjectTokenLength used in token exchange flows. MaxIDTokenHintLength = 64 * 1024 // 64KB // MaxACRValuesLength is the maximum length for the acr_values parameter. // ACR values are typically short URNs, but can be space-separated lists. MaxACRValuesLength = 1024 // MaxPromptLength is the maximum length for the prompt parameter. // Valid values are "none", "login", "consent", "select_account" or combinations. // Even with all combined ("login consent select_account"), this is well under 100 chars. MaxPromptLength = 128 // MaxMaxAgeLength is the maximum length for the max_age parameter (in seconds). // This caps parsing work for untrusted input. MaxMaxAgeLength = 10 // MaxMaxAgeSeconds caps max_age to a reasonable window (31 days). // Values above this are ignored to reduce DoS risk from huge integers. MaxMaxAgeSeconds = 31 * 24 * 60 * 60 )
OIDC parameter validation constants (OpenID Connect Core 1.0 Section 3.1.2.1) These limits provide defense-in-depth against DoS attacks via oversized parameters.
const ( ErrorCodeInvalidRequest = "invalid_request" ErrorCodeInvalidGrant = "invalid_grant" ErrorCodeInvalidClient = "invalid_client" ErrorCodeInvalidScope = "invalid_scope" ErrorCodeInvalidToken = "invalid_token" ErrorCodeInsufficientScope = "insufficient_scope" ErrorCodeUnsupportedGrantType = "unsupported_grant_type" ErrorCodeServerError = "server_error" ErrorCodeAccessDenied = "access_denied" ErrorCodeInvalidRedirectURI = "invalid_redirect_uri" ErrorCodeRateLimitExceeded = "rate_limit_exceeded" // Silent authentication error codes (OIDC Core Section 3.1.2.6) // These indicate the IdP requires user interaction and silent auth failed. ErrorCodeLoginRequired = "login_required" ErrorCodeConsentRequired = "consent_required" ErrorCodeInteractionRequired = "interaction_required" ErrorCodeAccountSelectionRequired = "account_selection_required" )
OAuth error codes as constants
const (
// OAuthSpecVersion is the OAuth specification version this library implements
OAuthSpecVersion = "OAuth 2.1"
)
OAuth specification version
Variables ¶
var ( // AllowedHTTPSchemes lists allowed HTTP-based redirect URI schemes AllowedHTTPSchemes = []string{"http", "https"} // DangerousSchemes lists URI schemes that must never be allowed for security DangerousSchemes = []string{"javascript", "data", "file", "vbscript", "about"} // DefaultRFC3986SchemePattern is the default regex pattern for custom URI schemes (RFC 3986) DefaultRFC3986SchemePattern = []string{"^[a-z][a-z0-9+.-]*$"} // LoopbackAddresses lists recognized loopback addresses for development LoopbackAddresses = []string{"localhost", "127.0.0.1", "::1", "[::1]"} )
Redirect URI validation constants
var ( // DefaultGrantTypes are the grant types supported by default DefaultGrantTypes = []string{"authorization_code", "refresh_token"} // DefaultResponseTypes are the response types supported by default DefaultResponseTypes = []string{"code"} // SupportedCodeChallengeMethods are the PKCE methods we support // Security: Only S256 is allowed. "plain" method is insecure and violates OAuth 2.1 SupportedCodeChallengeMethods = []string{"S256"} // SupportedTokenAuthMethods are the supported token endpoint auth methods SupportedTokenAuthMethods = []string{"client_secret_basic", "client_secret_post", "none"} )
OAuth grant types and response types
var ( // ErrInvalidRequest indicates the request is malformed or missing required parameters ErrInvalidRequest = func(desc string) *Error { return NewError(ErrorCodeInvalidRequest, desc, http.StatusBadRequest) } // ErrInvalidGrant indicates the authorization code or refresh token is invalid or expired ErrInvalidGrant = func(desc string) *Error { return NewError(ErrorCodeInvalidGrant, desc, http.StatusBadRequest) } // ErrInvalidClient indicates client authentication failed ErrInvalidClient = func(desc string) *Error { return NewError(ErrorCodeInvalidClient, desc, http.StatusUnauthorized) } // ErrInvalidScope indicates the requested scope is invalid or unsupported ErrInvalidScope = func(desc string) *Error { return NewError(ErrorCodeInvalidScope, desc, http.StatusBadRequest) } // ErrInvalidToken indicates the access token is invalid or expired ErrInvalidToken = func(desc string) *Error { return NewError(ErrorCodeInvalidToken, desc, http.StatusUnauthorized) } // ErrInsufficientScope indicates the access token lacks required scopes ErrInsufficientScope = func(desc string) *Error { return NewError(ErrorCodeInsufficientScope, desc, http.StatusForbidden) } ErrUnauthorizedClient = func(desc string) *Error { return NewError(ErrorCodeUnauthorizedClient, desc, http.StatusBadRequest) } // ErrUnsupportedGrantType indicates the grant type is not supported ErrUnsupportedGrantType = func(desc string) *Error { return NewError(ErrorCodeUnsupportedGrantType, desc, http.StatusBadRequest) } // ErrServerError indicates an internal server error occurred ErrServerError = func(desc string) *Error { return NewError(ErrorCodeServerError, desc, http.StatusInternalServerError) } // ErrAccessDenied indicates the user or authorization server denied the request ErrAccessDenied = func(desc string) *Error { return NewError(ErrorCodeAccessDenied, desc, http.StatusForbidden) } // ErrInvalidRedirectURI indicates the redirect URI is invalid or not registered ErrInvalidRedirectURI = func(desc string) *Error { return NewError(ErrorCodeInvalidRedirectURI, desc, http.StatusBadRequest) } )
Common OAuth errors as reusable instances
var ErrSilentAuthFailed = errors.New("silent authentication failed: user interaction required")
ErrSilentAuthFailed is a sentinel error for when silent authentication is not possible. This occurs when the IdP requires user interaction (login or consent) but the authorization request used prompt=none for silent authentication.
Use IsSilentAuthError to check if an error indicates silent auth failure.
var NewOAuthError = NewError
NewOAuthError is an alias for NewError, provided for backward compatibility.
Deprecated: Use NewError instead. This alias will be removed in a future major version.
Functions ¶
func ContextWithUserInfo ¶ added in v0.1.51
ContextWithUserInfo creates a context with the given user info. This is useful for testing code that depends on authenticated user context.
WARNING: This function should ONLY be used for testing. In production, user info should ONLY be set by the ValidateToken middleware after proper token validation. Using this function to bypass authentication in production code is a security vulnerability.
Note: if userInfo is nil, UserInfoFromContext will return (nil, true). Callers should check both the ok value and nil-ness of the returned userInfo.
func InterstitialAppName ¶ added in v0.1.48
InterstitialAppName extracts the application name from the request context. This is used by custom interstitial handlers to get the human-readable app name. Returns empty string if not found in context.
func InterstitialRedirectURL ¶ added in v0.1.48
InterstitialRedirectURL extracts the OAuth redirect URL from the request context. This is used by custom interstitial handlers to get the redirect URL. Returns empty string if not found in context.
func IsSilentAuthError ¶ added in v0.2.46
IsSilentAuthError returns true if the error indicates silent authentication failed and interactive login is required. This checks for:
- *SilentAuthError type (including wrapped errors)
- Error strings containing known silent auth error codes
Example usage:
result := handleCallback(r)
if err := result.Err(); err != nil {
if oauth.IsSilentAuthError(err) {
// Fall back to interactive login
return startInteractiveLogin(w, r)
}
// Handle other errors
return handleError(w, err)
}
func ParseOAuthError ¶ added in v0.2.46
ParseOAuthError parses an OAuth error response and returns the appropriate error type. For silent auth failure codes (login_required, consent_required, interaction_required, account_selection_required), returns a *SilentAuthError. For other errors, returns a generic *Error with the code and description. Returns nil if errorCode is empty.
Example usage:
err := oauth.ParseOAuthError(r.URL.Query().Get("error"), r.URL.Query().Get("error_description"))
if err != nil {
if oauth.IsSilentAuthError(err) {
// Handle silent auth failure
}
}
Types ¶
type AuthorizationServerMetadata ¶
type AuthorizationServerMetadata struct {
// Issuer is the authorization server's issuer identifier URL
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"`
// RegistrationEndpoint is the URL of the dynamic client registration endpoint (RFC 7591)
RegistrationEndpoint string `json:"registration_endpoint,omitempty"`
// ScopesSupported lists the OAuth scopes supported
ScopesSupported []string `json:"scopes_supported,omitempty"`
// ResponseTypesSupported lists the OAuth response types supported
ResponseTypesSupported []string `json:"response_types_supported"`
// GrantTypesSupported lists the OAuth grant types supported
GrantTypesSupported []string `json:"grant_types_supported,omitempty"`
// TokenEndpointAuthMethodsSupported lists the client authentication methods supported at the token endpoint
TokenEndpointAuthMethodsSupported []string `json:"token_endpoint_auth_methods_supported,omitempty"`
// CodeChallengeMethodsSupported lists the PKCE code challenge methods supported
CodeChallengeMethodsSupported []string `json:"code_challenge_methods_supported,omitempty"`
// RevocationEndpoint is the URL of the OAuth 2.0 token revocation endpoint (RFC 7009)
RevocationEndpoint string `json:"revocation_endpoint,omitempty"`
// IntrospectionEndpoint is the URL of the OAuth 2.0 token introspection endpoint (RFC 7662)
IntrospectionEndpoint string `json:"introspection_endpoint,omitempty"`
// ClientIDMetadataDocumentSupported indicates support for Client ID Metadata Documents (MCP 2025-11-25)
ClientIDMetadataDocumentSupported bool `json:"client_id_metadata_document_supported,omitempty"`
}
AuthorizationServerMetadata represents OAuth 2.0 Authorization Server Metadata (RFC 8414)
type CallbackResult ¶ added in v0.2.46
type CallbackResult struct {
// Code is the authorization code from a successful authorization.
// Empty if the callback contains an error.
Code string
// State is the state parameter for CSRF validation.
// Should match the state sent in the authorization request.
State string
// Error is the OAuth error code if authorization failed.
// Common values: "access_denied", "login_required", "consent_required"
Error string
// ErrorDescription provides additional information about the error.
// Human-readable text describing the error.
ErrorDescription string
// ErrorURI points to a web page with error documentation.
ErrorURI string
}
CallbackResult represents the result of an OAuth authorization callback. It parses and holds the query parameters from the OAuth redirect.
The callback may contain either:
- Success: Code and State parameters
- Error: Error, ErrorDescription, and optionally ErrorURI parameters
Use Err() to get a typed error for error responses, including SilentAuthError for silent authentication failures.
func ParseCallbackQuery ¶ added in v0.2.46
func ParseCallbackQuery(code, state, errorCode, errorDescription, errorURI string) *CallbackResult
ParseCallbackQuery creates a CallbackResult from URL query parameters. This is a convenience function for parsing OAuth callback query strings.
Parameters:
- code: The authorization code (from "code" query param)
- state: The state parameter (from "state" query param)
- errorCode: The error code (from "error" query param)
- errorDescription: The error description (from "error_description" query param)
- errorURI: The error URI (from "error_uri" query param)
func (*CallbackResult) Err ¶ added in v0.2.46
func (r *CallbackResult) Err() error
Err returns an appropriate error for the callback result. For silent auth failures (login_required, consent_required, interaction_required, account_selection_required), returns a *SilentAuthError that can be detected with IsSilentAuthError(). Returns nil if no error occurred.
Example usage:
q := r.URL.Query()
result := ParseCallbackQuery(q.Get("code"), q.Get("state"), q.Get("error"), q.Get("error_description"), q.Get("error_uri"))
if err := result.Err(); err != nil {
if IsSilentAuthError(err) {
// Fall back to interactive login
return startInteractiveLogin(w, r)
}
return handleError(w, err)
}
// Process result.Code
func (*CallbackResult) IsError ¶ added in v0.2.46
func (r *CallbackResult) IsError() bool
IsError returns true if the callback contains an error. Use Err() to get the actual error with proper typing.
type ClientRegistrationRequest ¶
type ClientRegistrationRequest struct {
// RedirectURIs is the array of redirection URIs for use in redirect-based flows
RedirectURIs []string `json:"redirect_uris,omitempty"`
// TokenEndpointAuthMethod is the requested authentication method for the token endpoint
TokenEndpointAuthMethod string `json:"token_endpoint_auth_method,omitempty"`
// GrantTypes is the array of OAuth 2.0 grant types the client will use
GrantTypes []string `json:"grant_types,omitempty"`
// ResponseTypes is the array of OAuth 2.0 response types the client will use
ResponseTypes []string `json:"response_types,omitempty"`
// ClientName is the human-readable name of the client
ClientName string `json:"client_name,omitempty"`
// ClientURI is the URL of the client's home page
ClientURI string `json:"client_uri,omitempty"`
// Scope is the space-separated list of scope values
Scope string `json:"scope,omitempty"`
// ClientType indicates if this is a "public" or "confidential" client
// Public clients (mobile, SPA) can use "none" auth method
// Confidential clients (server-side) must use client_secret_basic or client_secret_post
ClientType string `json:"client_type,omitempty"`
}
ClientRegistrationRequest represents a dynamic client registration request
type ClientRegistrationResponse ¶
type ClientRegistrationResponse struct {
// ClientID is the unique client identifier
ClientID string `json:"client_id"`
// ClientSecret is the client secret (for confidential clients)
ClientSecret string `json:"client_secret,omitempty"`
// ClientIDIssuedAt is the time the client_id was issued
ClientIDIssuedAt int64 `json:"client_id_issued_at,omitempty"`
// ClientSecretExpiresAt is when the client_secret expires (0 = never)
ClientSecretExpiresAt int64 `json:"client_secret_expires_at,omitempty"`
// RedirectURIs is the array of redirection URIs
RedirectURIs []string `json:"redirect_uris,omitempty"`
// TokenEndpointAuthMethod is the authentication method for the token endpoint
TokenEndpointAuthMethod string `json:"token_endpoint_auth_method,omitempty"`
// GrantTypes is the array of OAuth 2.0 grant types
GrantTypes []string `json:"grant_types,omitempty"`
// ResponseTypes is the array of OAuth 2.0 response types
ResponseTypes []string `json:"response_types,omitempty"`
// ClientName is the human-readable name of the client
ClientName string `json:"client_name,omitempty"`
// Scope is the space-separated list of scope values
Scope string `json:"scope,omitempty"`
// ClientType indicates if this is a "public" or "confidential" client
ClientType string `json:"client_type,omitempty"`
}
ClientRegistrationResponse represents a dynamic client registration response
type Config ¶
type Config struct {
// Resource is the MCP server resource identifier for RFC 8707
// This should be the base URL of the MCP server
Resource string
// SupportedScopes are all available Google API scopes
SupportedScopes []string
// Google OAuth credentials and settings
GoogleAuth GoogleAuthConfig
// Rate limiting configuration
RateLimit RateLimitConfig
// Security settings (secure by default)
Security SecurityConfig
// CleanupInterval is how often to cleanup expired tokens
// Default: 1 minute
CleanupInterval time.Duration
// Logger for structured logging (optional, uses default if not provided)
Logger *slog.Logger
// HTTPClient is a custom HTTP client for OAuth requests
// If not provided, uses the default HTTP client
// Can be used to add timeouts, logging, metrics, etc.
HTTPClient *http.Client
}
Config holds the OAuth handler configuration Structured using composition for better organization and maintainability
type Error ¶ added in v0.2.24
type Error struct {
Code string // OAuth error code (e.g., "invalid_request", "invalid_grant")
Description string // Human-readable error description
Status int // HTTP status code
}
Error represents an OAuth 2.0 error response. This type implements the standard error interface and provides structured information about OAuth protocol errors.
type ErrorResponse ¶
type ErrorResponse struct {
// Error is the error code
Error string `json:"error"`
// ErrorDescription provides additional information
ErrorDescription string `json:"error_description,omitempty"`
// ErrorURI points to error documentation
ErrorURI string `json:"error_uri,omitempty"`
}
ErrorResponse represents an OAuth error response
type GoogleAuthConfig ¶
type GoogleAuthConfig struct {
// ClientID is the Google OAuth Client ID (required).
ClientID string
// ClientSecret is the Google OAuth Client Secret (required).
ClientSecret string
// RedirectURL is where Google redirects after authentication.
RedirectURL string
}
GoogleAuthConfig holds Google OAuth proxy configuration
type Handler ¶
type Handler struct {
// contains filtered or unexported fields
}
Handler is a thin HTTP adapter for the OAuth Server. It handles HTTP requests and delegates to the Server for business logic.
func NewHandler ¶
NewHandler creates a new HTTP handler
func (*Handler) RegisterAuthorizationServerMetadataRoutes ¶ added in v0.1.53
RegisterAuthorizationServerMetadataRoutes registers all Authorization Server Metadata discovery routes. This supports multi-tenant deployments with path-based issuers per MCP 2025-11-25.
For issuer URLs with path components (e.g., https://auth.example.com/tenant1), registers:
- Path insertion OAuth: /.well-known/oauth-authorization-server/tenant1
- Path insertion OIDC: /.well-known/openid-configuration/tenant1
- Path appending OIDC: /tenant1/.well-known/openid-configuration
For issuer URLs without path components (e.g., https://auth.example.com), registers:
- Standard OAuth: /.well-known/oauth-authorization-server
- Standard OIDC: /.well-known/openid-configuration
Example usage:
// Single-tenant: Configure issuer without path
config := &ServerConfig{
Issuer: "https://auth.example.com",
}
// Registers: /.well-known/oauth-authorization-server
// /.well-known/openid-configuration
handler.RegisterAuthorizationServerMetadataRoutes(mux)
// Multi-tenant: Configure issuer with path
config := &ServerConfig{
Issuer: "https://auth.example.com/tenant1",
}
// Registers: /.well-known/oauth-authorization-server/tenant1
// /.well-known/openid-configuration/tenant1
// /tenant1/.well-known/openid-configuration
// (plus standard endpoints for backward compatibility)
handler.RegisterAuthorizationServerMetadataRoutes(mux)
func (*Handler) RegisterProtectedResourceMetadataRoutes ¶ added in v0.1.35
RegisterProtectedResourceMetadataRoutes registers all Protected Resource Metadata discovery routes. It registers the root endpoint and optional sub-path endpoints based on configuration.
Route registration is done for:
- Root endpoint: /.well-known/oauth-protected-resource (always registered)
- Explicit mcpPath endpoint if provided (backward compatibility)
- All paths from ResourceMetadataByPath configuration (MCP 2025-11-25)
Security: This function validates all paths to prevent path traversal attacks and DoS through excessively long paths. Invalid paths are logged and skipped.
Example usage:
// Legacy single-path registration handler.RegisterProtectedResourceMetadataRoutes(mux, "/mcp") // With per-path configuration (new in MCP 2025-11-25) // Configure in server.Config.ResourceMetadataByPath, then: handler.RegisterProtectedResourceMetadataRoutes(mux, "") // This registers routes for all configured paths automatically
func (*Handler) ServeAuthorization ¶
func (h *Handler) ServeAuthorization(w http.ResponseWriter, r *http.Request)
ServeAuthorization handles OAuth authorization requests
func (*Handler) ServeAuthorizationServerMetadata ¶
func (h *Handler) ServeAuthorizationServerMetadata(w http.ResponseWriter, r *http.Request)
ServeAuthorizationServerMetadata serves RFC 8414 Authorization Server Metadata
func (*Handler) ServeCallback ¶
func (h *Handler) ServeCallback(w http.ResponseWriter, r *http.Request)
ServeCallback handles the OAuth provider callback
func (*Handler) ServeClientRegistration ¶
func (h *Handler) ServeClientRegistration(w http.ResponseWriter, r *http.Request)
ServeClientRegistration handles dynamic client registration (RFC 7591)
func (*Handler) ServeOpenIDConfiguration ¶ added in v0.1.43
func (h *Handler) ServeOpenIDConfiguration(w http.ResponseWriter, r *http.Request)
ServeOpenIDConfiguration handles OpenID Connect Discovery 1.0 requests Per RFC 8414 Section 5, this endpoint returns the same metadata as the Authorization Server Metadata endpoint for compatibility with OpenID Connect clients
func (*Handler) ServePreflightRequest ¶ added in v0.1.22
func (h *Handler) ServePreflightRequest(w http.ResponseWriter, r *http.Request)
ServePreflightRequest handles CORS preflight (OPTIONS) requests. Required for non-simple requests (POST with JSON, custom headers, etc.).
func (*Handler) ServeProtectedResourceMetadata ¶
func (h *Handler) ServeProtectedResourceMetadata(w http.ResponseWriter, r *http.Request)
ServeProtectedResourceMetadata serves RFC 9728 Protected Resource Metadata with support for path-specific metadata discovery per MCP 2025-11-25.
The handler extracts the resource path from the request URL and looks up path-specific configuration in ResourceMetadataByPath. If a match is found, path-specific metadata is returned; otherwise, default server-wide metadata is used.
Path matching uses longest-prefix matching. For example, given paths "/mcp/files" and "/mcp/files/admin", a request for "/mcp/files/admin/users" would match "/mcp/files/admin".
func (*Handler) ServeToken ¶
func (h *Handler) ServeToken(w http.ResponseWriter, r *http.Request)
ServeToken handles the OAuth token endpoint
func (*Handler) ServeTokenIntrospection ¶ added in v0.1.1
func (h *Handler) ServeTokenIntrospection(w http.ResponseWriter, r *http.Request)
ServeTokenIntrospection handles the RFC 7662 token introspection endpoint This allows resource servers to validate access tokens Security: Requires client authentication to prevent token scanning attacks
func (*Handler) ServeTokenRevocation ¶
func (h *Handler) ServeTokenRevocation(w http.ResponseWriter, r *http.Request)
ServeTokenRevocation handles the RFC 7009 token revocation endpoint
type InstrumentationConfig ¶ added in v0.1.26
type InstrumentationConfig = server.InstrumentationConfig
InstrumentationConfig is a type alias for backward compatibility. Use server.InstrumentationConfig for new code.
type OAuthError
deprecated
type OAuthError = Error
OAuthError is an alias for Error, provided for backward compatibility.
Deprecated: Use Error instead. This alias will be removed in a future major version.
type ProtectedResourceMetadata ¶
type ProtectedResourceMetadata struct {
// Resource is the identifier for the protected resource
Resource string `json:"resource"`
// AuthorizationServers lists the authorization servers that can issue tokens for this resource
AuthorizationServers []string `json:"authorization_servers"`
// BearerMethodsSupported lists the ways Bearer tokens can be sent (RFC 6750)
BearerMethodsSupported []string `json:"bearer_methods_supported,omitempty"`
// ResourceSigningAlgValuesSupported lists supported signing algorithms
ResourceSigningAlgValuesSupported []string `json:"resource_signing_alg_values_supported,omitempty"`
// ScopesSupported lists the scopes understood by this resource
ScopesSupported []string `json:"scopes_supported,omitempty"`
}
ProtectedResourceMetadata represents OAuth 2.0 Protected Resource Metadata (RFC 9728)
type RateLimitConfig ¶
type RateLimitConfig struct {
// Rate is requests per second allowed per IP. Zero disables limiting.
Rate int
// Burst is the maximum burst size allowed per IP.
Burst int
// CleanupInterval is how often to cleanup inactive rate limiters.
CleanupInterval time.Duration
// UserRate is requests per second allowed per authenticated user.
// Applied in addition to IP-based limiting. Zero disables.
UserRate int
// UserBurst is the maximum burst size per authenticated user.
UserBurst int
// TrustProxy enables trusting X-Forwarded-For and X-Real-IP headers.
// Only enable behind a trusted reverse proxy.
TrustProxy bool
}
RateLimitConfig holds rate limiting configuration
type SecurityConfig ¶
type SecurityConfig struct {
// AllowInsecureAuthWithoutState permits auth requests without state parameter.
// WARNING: Weakens CSRF protection. Only for legacy clients.
AllowInsecureAuthWithoutState bool
// DisableRefreshTokenRotation disables automatic refresh token rotation.
// WARNING: Violates OAuth 2.1. Stolen tokens remain valid indefinitely.
DisableRefreshTokenRotation bool
// AllowPublicClientRegistration permits unauthenticated client registration.
// WARNING: Can enable DoS via mass registration.
AllowPublicClientRegistration bool
// RegistrationAccessToken is required for client registration when
// AllowPublicClientRegistration is false.
RegistrationAccessToken string
// RefreshTokenTTL is how long refresh tokens remain valid.
// Recommended: 30-90 days. Zero means never expire.
RefreshTokenTTL time.Duration
// MaxClientsPerIP limits registrations per IP to prevent DoS.
// Zero means no limit (not recommended).
MaxClientsPerIP int
// AllowCustomRedirectSchemes permits non-http/https URIs (e.g., myapp://).
// Custom schemes are validated against AllowedCustomSchemes patterns.
AllowCustomRedirectSchemes bool
// AllowedCustomSchemes lists allowed custom URI scheme regex patterns.
// Default: RFC 3986 compliant schemes.
AllowedCustomSchemes []string
// EncryptionKey is the AES-256 key (32 bytes) for token encryption at rest.
// Nil disables encryption. Generate with oauth.GenerateEncryptionKey().
EncryptionKey []byte
// EnableAuditLogging enables security audit logging.
// Logs auth events, token operations, and violations (sensitive data hashed).
EnableAuditLogging bool
}
SecurityConfig holds OAuth security settings (secure by default)
type Server ¶
Server is a type alias for backward compatibility. All server logic is now in the server package.
func NewServer ¶
func NewServer( provider providers.Provider, tokenStore storage.TokenStore, clientStore storage.ClientStore, flowStore storage.FlowStore, config *ServerConfig, logger *slog.Logger, ) (*Server, error)
NewServer creates a new OAuth server. This is a convenience wrapper for server.New() to maintain backward compatibility.
type ServerConfig ¶
ServerConfig is a type alias for backward compatibility. Use server.Config for new code.
type SilentAuthError ¶ added in v0.2.46
type SilentAuthError struct {
// Code is the OAuth/OIDC error code.
// Common values: "login_required", "consent_required", "interaction_required"
Code string
// Description is the optional error description from the IdP
Description string
}
SilentAuthError represents an error from a silent authentication attempt. These errors indicate the IdP requires user interaction and the client should fall back to interactive login.
Silent authentication fails when:
- No active session at the IdP (login_required)
- User hasn't granted required scopes (consent_required)
- IdP needs user interaction for other reasons (interaction_required)
- Multiple accounts and none selected (account_selection_required)
See: https://openid.net/specs/openid-connect-core-1_0.html#AuthError
func (*SilentAuthError) Error ¶ added in v0.2.46
func (e *SilentAuthError) Error() string
Error implements the error interface.
type TokenResponse ¶
type TokenResponse struct {
// AccessToken is the access token
AccessToken string `json:"access_token"`
// TokenType is the type of token (always "Bearer")
TokenType string `json:"token_type"`
// ExpiresIn is the lifetime in seconds of the access token
ExpiresIn int64 `json:"expires_in,omitempty"`
// RefreshToken is the refresh token (optional)
RefreshToken string `json:"refresh_token,omitempty"`
// Scope is the scope of the access token
Scope string `json:"scope,omitempty"`
// IDToken is the OIDC ID token from the upstream provider (optional).
// Per OpenID Connect Core 1.0 Section 3.1.3.3, this is REQUIRED for OIDC flows.
// This enables clients to use id_token_hint and login_hint for silent re-authentication.
IDToken string `json:"id_token,omitempty"`
}
TokenResponse represents an OAuth 2.0 token response
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
examples
|
|
|
basic
command
Package main demonstrates basic OAuth 2.1 setup for MCP servers.
|
Package main demonstrates basic OAuth 2.1 setup for MCP servers. |
|
cimd
command
Package main demonstrates Client ID Metadata Document (CIMD) verification.
|
Package main demonstrates Client ID Metadata Document (CIMD) verification. |
|
custom-scopes
command
Package main demonstrates OAuth setup with multiple Google API scopes.
|
Package main demonstrates OAuth setup with multiple Google API scopes. |
|
dex
command
Package main demonstrates OAuth setup with the Dex OIDC provider.
|
Package main demonstrates OAuth setup with the Dex OIDC provider. |
|
github
command
Package main demonstrates OAuth setup with the GitHub OAuth provider.
|
Package main demonstrates OAuth setup with the GitHub OAuth provider. |
|
mcp-2025-11-25
command
Package main demonstrates MCP 2025-11-25 OAuth specification features.
|
Package main demonstrates MCP 2025-11-25 OAuth specification features. |
|
production
command
Package main demonstrates production-ready OAuth 2.1 setup for MCP servers.
|
Package main demonstrates production-ready OAuth 2.1 setup for MCP servers. |
|
prometheus
command
Package main demonstrates OAuth setup with Prometheus metrics.
|
Package main demonstrates OAuth setup with Prometheus metrics. |
|
Package instrumentation provides OpenTelemetry (OTEL) instrumentation for the mcp-oauth library.
|
Package instrumentation provides OpenTelemetry (OTEL) instrumentation for the mcp-oauth library. |
|
internal
|
|
|
helpers
Package helpers provides common utility functions used across the mcp-oauth library.
|
Package helpers provides common utility functions used across the mcp-oauth library. |
|
testutil
Package testutil provides testing utilities, mock implementations, and test fixtures for the mcp-oauth library.
|
Package testutil provides testing utilities, mock implementations, and test fixtures for the mcp-oauth library. |
|
Package providers defines the OAuth provider interface and types for user information.
|
Package providers defines the OAuth provider interface and types for user information. |
|
dex
Package dex implements the OAuth provider interface for Dex (https://dexidp.io/).
|
Package dex implements the OAuth provider interface for Dex (https://dexidp.io/). |
|
github
Package github implements the OAuth provider interface for GitHub OAuth Apps.
|
Package github implements the OAuth provider interface for GitHub OAuth Apps. |
|
google
Package google provides a Google OAuth 2.0 provider implementation.
|
Package google provides a Google OAuth 2.0 provider implementation. |
|
mock
Package mock provides mock implementations of the Provider interface for testing purposes.
|
Package mock provides mock implementations of the Provider interface for testing purposes. |
|
oidc
Package oidc provides shared OpenID Connect client utilities for OAuth providers.
|
Package oidc provides shared OpenID Connect client utilities for OAuth providers. |
|
Package security provides security features for OAuth including encryption, rate limiting, audit logging, and secure header management.
|
Package security provides security features for OAuth including encryption, rate limiting, audit logging, and secure header management. |
|
Package server provides OAuth 2.1 authorization server implementation with MCP support
|
Package server provides OAuth 2.1 authorization server implementation with MCP support |
|
Package storage provides interfaces and utilities for OAuth token, client, and flow persistence.
|
Package storage provides interfaces and utilities for OAuth token, client, and flow persistence. |
|
memory
Package memory provides an in-memory implementation of the OAuth storage interfaces.
|
Package memory provides an in-memory implementation of the OAuth storage interfaces. |
|
mock
Package mock provides mock implementations of storage interfaces for testing purposes.
|
Package mock provides mock implementations of storage interfaces for testing purposes. |
|
valkey
Package valkey provides a Valkey storage backend for the mcp-oauth library.
|
Package valkey provides a Valkey storage backend for the mcp-oauth library. |