providers

package
v0.2.166 Latest Latest
Warning

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

Go to latest
Published: May 27, 2026 License: Apache-2.0 Imports: 6 Imported by: 1

Documentation

Overview

Package providers defines the OAuth provider interface and types for user information.

This package contains the Provider interface that must be implemented by all OAuth identity providers, as well as the UserInfo type that represents authenticated user data.

Interfaces

Provider is the core interface that all OAuth identity providers must implement. It handles the complete OAuth flow including authorization, token exchange, validation, refresh, and revocation.

JWKSProvider is an optional interface for providers that support JWKS-based JWT validation. This enables SSO token forwarding where ID tokens from upstream servers can be validated via JWKS signature verification instead of calling the userinfo endpoint. Providers that implement this interface can participate in federated authentication scenarios.

Implementations

Implementations are provided in subpackages:

  • providers/google: Google OAuth 2.0 provider (implements JWKSProvider)
  • providers/github: GitHub OAuth provider
  • providers/dex: Dex OIDC provider (implements JWKSProvider, supports multiple connectors)
  • providers/mock: Mock provider for testing (implements JWKSProvider)
  • providers/oidc: Generic OIDC discovery and validation utilities

Provider Capabilities

All Provider implementations handle:

  • OAuth authorization URL generation with PKCE support
  • Authorization code exchange
  • Token validation and user info retrieval
  • Token refresh
  • Token revocation
  • Health checks

JWKSProvider implementations additionally support:

  • JWKS URI discovery for JWT signature verification
  • Issuer URL for JWT issuer validation

Example Usage

Basic provider usage:

provider, err := google.NewProvider(&google.Config{
    ClientID:     "your-client-id",
    ClientSecret: "your-client-secret",
    RedirectURL:  "http://localhost:8080/oauth/callback",
})
if err != nil {
    log.Fatal(err)
}

// Use provider with OAuth server
server, _ := oauth.NewServer(provider, tokenStore, clientStore, flowStore, config, logger)

SSO Token Forwarding

When using TrustedAudiences with a JWKSProvider, the server can validate forwarded ID tokens from upstream MCP servers:

config := &server.Config{
    TrustedAudiences: []string{"upstream-client-id"},
    // ... other config
}

The server will:

  1. Check if the Bearer token is a JWT with a matching audience
  2. Validate the JWT signature using the provider's JWKS
  3. Extract user info from the validated ID token claims

Package providers defines the interface for OAuth identity providers and implements provider-specific logic for Google, GitHub, Microsoft, and other OAuth/OIDC providers.

Index

Constants

View Source
const CrossClientAudienceScopePrefix = "audience:server:client_id:"

CrossClientAudienceScopePrefix is the Dex-specific prefix for cross-client audience scopes. Scopes with this prefix are mandatory and must be merged into client-requested scopes to enable SSO token forwarding scenarios.

ADMINISTRATOR NOTE: Any scope with this prefix configured in the provider's default scopes will be AUTOMATICALLY MERGED into ALL authorization requests, regardless of what scopes the client explicitly requests. This is intentional behavior to ensure SSO token forwarding works correctly, but administrators should be aware that:

  • Tokens will always include the configured audience claims
  • Clients cannot opt out of these audiences
  • This affects token size and validation requirements on downstream services

Example: If defaults include "audience:server:client_id:k8s-auth", every token will be valid for the "k8s-auth" client, even if the requesting client didn't ask for it.

Variables

This section is empty.

Functions

func ApplyAuthorizationURLOptions added in v0.2.46

func ApplyAuthorizationURLOptions(opts *AuthorizationURLOptions) []oauth2.AuthCodeOption

ApplyAuthorizationURLOptions converts AuthorizationURLOptions to oauth2.AuthCodeOption slice. This shared helper reduces code duplication across providers and helps keep cyclomatic complexity low. Returns nil if opts is nil.

Standard OIDC parameters supported:

  • prompt: Controls authentication UX (none, login, consent, select_account)
  • login_hint: Pre-fills username/email field
  • max_age: Maximum authentication age in seconds
  • acr_values: Authentication context class references
  • id_token_hint: Previously issued ID token as session hint
  • Extra: Additional custom parameters

func CloneScopes added in v0.2.136

func CloneScopes(scopes []string) []string

CloneScopes returns an independent copy of scopes (nil-safe). Used by every provider's DefaultScopes() so callers cannot mutate the provider's slice.

func CopyScopes added in v0.2.46

func CopyScopes(requestedScopes, defaultScopes []string) []string

CopyScopes creates a deep copy of scopes to prevent race conditions. If requestedScopes is empty, copies defaultScopes. If requestedScopes is non-empty, copies those and merges in any mandatory scopes from defaultScopes. Mandatory scopes (when present in defaults) are:

  • "openid": Required by OIDC spec.
  • "email": Required for user identification in downstream services.
  • "profile": Required for user display name and metadata.
  • "groups": Required for RBAC-based authorization.
  • "offline_access": Required for refresh token issuance.
  • Cross-client audience scopes (prefixed with CrossClientAudienceScopePrefix): Required for SSO token forwarding scenarios.

Example:

defaultScopes: ["openid", "profile", "email", "groups", "offline_access", "audience:server:client_id:k8s-auth"]
requestedScopes: ["claudeai"]
result: ["claudeai", "openid", "profile", "email", "groups", "offline_access", "audience:server:client_id:k8s-auth"]

All identity-critical scopes from defaults are force-merged, ensuring that downstream services always receive the claims they need (email, groups, etc.) regardless of what the MCP client explicitly requests.

func EnsureTimeout added in v0.2.136

func EnsureTimeout(ctx context.Context, timeout time.Duration) (context.Context, context.CancelFunc)

EnsureTimeout returns ctx unchanged when it already has a deadline; otherwise it returns context.WithTimeout(ctx, timeout). The cancel func is always non-nil and safe to defer.

func ExchangeCodeWithPKCE added in v0.2.24

func ExchangeCodeWithPKCE(ctx context.Context, config OAuth2ConfigExchanger, httpClient *http.Client, code, verifier string) (*oauth2.Token, error)

ExchangeCodeWithPKCE is a shared helper for exchanging authorization codes with optional PKCE. It handles the common pattern of: 1. Adding PKCE verifier if provided 2. Setting up the HTTP client context 3. Performing the exchange 4. Wrapping any errors consistently

Parameters:

  • ctx: context for the request (should have timeout set by caller)
  • config: OAuth2 config that implements Exchange method
  • httpClient: custom HTTP client to use for the exchange
  • code: the authorization code to exchange
  • verifier: PKCE code verifier (empty string if not using PKCE)

func FilterScopes added in v0.2.136

func FilterScopes(requestedScopes, defaultScopes []string, supported func(string) bool) []string

FilterScopes applies the provider-specific `supported` predicate to the merged copy that CopyScopes produces from requestedScopes+defaultScopes. Mandatory-scope merging (openid, email, etc.) happens inside CopyScopes; FilterScopes is the IdP-specific overlay that drops scopes the upstream would reject (e.g. Google does not accept Dex audience scopes, and vice versa).

A nil predicate is treated as "accept everything".

func IssuerOf added in v0.2.102

func IssuerOf(p Provider) string

IssuerOf returns the upstream OIDC issuer URL for a provider that implements JWKSProvider, or "" otherwise.

Not every Provider is an OIDC provider. GitHub's provider is OAuth 2.0 only — it has no OIDC issuer and no JWKS — so IssuerOf returns "" for it, which is the correct answer rather than a failure mode.

Callers that require an issuer (for example, forwarded-ID-token validation) should check for a non-empty return value and reject the request with a clear error when it is empty.

Types

type AuthorizationURLOptions added in v0.2.46

type AuthorizationURLOptions struct {
	// Prompt controls the authentication UX behavior.
	// Common values:
	//   - "none": Silent authentication - no UI displayed. Returns error if login/consent required.
	//   - "login": Force re-authentication even if session exists.
	//   - "consent": Force consent even if previously granted.
	//   - "select_account": Force account selection even if only one account.
	// Multiple values can be space-separated: "login consent"
	Prompt string

	// LoginHint pre-fills the email/username field at the IdP.
	// Useful for re-authentication when the user's identity is already known.
	// Example: "user@example.com"
	LoginHint string

	// MaxAge specifies the maximum authentication age in seconds.
	// If the user's session is older than this, re-authentication is required.
	// A value of 0 is equivalent to prompt=login.
	MaxAge *int

	// ACRValues requests specific authentication context class references.
	// Space-separated string of acr_values.
	// Example: "urn:mace:incommon:iap:silver"
	ACRValues string

	// IDTokenHint is a previously issued ID token passed as a hint about the user's session.
	// Used with prompt=none to identify the user for silent re-authentication.
	IDTokenHint string

	// Nonce is forwarded to the IdP and must be echoed back in the resulting
	// id_token's `nonce` claim.
	Nonce string

	// Extra allows setting additional custom parameters not covered above.
	// These are added as query parameters to the authorization URL.
	Extra map[string]string
}

AuthorizationURLOptions contains optional OIDC parameters for the authorization request. These parameters enable advanced authentication flows like silent re-authentication and user hints per OpenID Connect Core 1.0 Section 3.1.2.1.

See: https://openid.net/specs/openid-connect-core-1_0.html#AuthRequest

type JWKSProvider added in v0.2.39

type JWKSProvider interface {
	Provider

	// JWKSURI returns the JWKS (JSON Web Key Set) URI for this provider.
	// This is used to fetch public keys for JWT signature verification.
	// Returns empty string if JWKS is not available.
	JWKSURI(ctx context.Context) (string, error)

	// IssuerURL returns the issuer URL for this provider.
	// This is used for JWT issuer validation.
	IssuerURL() string
}

JWKSProvider is an optional interface for providers that support JWKS-based JWT validation. This enables SSO token forwarding where ID tokens from upstream servers are validated via JWKS signature verification.

Providers that don't support JWKS validation can omit this interface. The server will fall back to userinfo endpoint validation in that case.

type OAuth2ConfigExchanger added in v0.2.24

type OAuth2ConfigExchanger interface {
	Exchange(ctx context.Context, code string, opts ...oauth2.AuthCodeOption) (*oauth2.Token, error)
}

OAuth2ConfigExchanger is an interface for the Exchange method of oauth2.Config. This allows us to create shared helper functions that work with any provider's config.

type Provider

type Provider interface {
	// Name returns the provider name (e.g., "google", "github", "microsoft")
	Name() string

	// DefaultScopes returns the provider's default scopes used when the client doesn't
	// request specific scopes. These are the scopes configured when the provider was created.
	DefaultScopes() []string

	// AuthorizationURL generates the URL to redirect users for authentication
	// codeChallenge and codeChallengeMethod are for PKCE (pass empty strings to disable)
	// scopes is the list of scopes to request (if empty, provider's default scopes are used)
	// opts contains optional OIDC parameters like prompt, login_hint, max_age (nil for defaults)
	//
	// OAuth 2.1 Security: PKCE is recommended for ALL client types (public and confidential)
	// to protect against Authorization Code Injection attacks. Providers should support PKCE
	// even when using client_secret authentication for defense-in-depth.
	AuthorizationURL(state string, codeChallenge string, codeChallengeMethod string, scopes []string, opts *AuthorizationURLOptions) string

	// ExchangeCode exchanges an authorization code for tokens
	// codeVerifier is for PKCE verification (pass empty string if not using PKCE)
	// Returns standard oauth2.Token
	//
	// OAuth 2.1 Security: PKCE verification provides cryptographic binding between the
	// authorization request and token exchange, preventing code injection even for
	// confidential clients with client_secret.
	ExchangeCode(ctx context.Context, code string, codeVerifier string) (*oauth2.Token, error)

	// ValidateToken validates an access token and returns user information
	ValidateToken(ctx context.Context, accessToken string) (*UserInfo, error)

	// RefreshToken refreshes an expired token using a refresh token
	// Returns standard oauth2.Token
	RefreshToken(ctx context.Context, refreshToken string) (*oauth2.Token, error)

	// RevokeToken revokes a token at the provider
	RevokeToken(ctx context.Context, token string) error

	// HealthCheck verifies that the provider is reachable and functioning correctly.
	// This is useful for readiness/liveness probes and startup validation.
	// Returns nil if the provider is healthy, or an error describing the issue.
	//
	// SECURITY WARNING: Do not expose error messages from this method to untrusted clients.
	// Error details may contain information about provider state (HTTP status codes, network errors)
	// that could be used for reconnaissance. Use this for internal monitoring only.
	HealthCheck(ctx context.Context) error
}

Provider defines the interface for OAuth identity providers. This abstraction allows supporting Google, GitHub, Microsoft, and generic OIDC providers. Now uses golang.org/x/oauth2.Token directly instead of custom types.

type TokenSource added in v0.2.43

type TokenSource string

TokenSource indicates how the user was authenticated.

const (
	// TokenSourceOAuth indicates the user was authenticated via normal OAuth flow.
	// The server issued the token and the provider's ID token is stored in the token store.
	TokenSourceOAuth TokenSource = "oauth"

	// TokenSourceSSO indicates the user was authenticated via SSO token forwarding.
	// The Bearer token IS the ID token forwarded from a trusted upstream service.
	// There is no entry in the token store because the server didn't issue the token.
	TokenSourceSSO TokenSource = "sso"

	// TokenSourceJWT indicates the user was authenticated via a self-issued
	// JWT access token (RFC 9068). The Bearer token IS a JWT signed by this
	// server's own access-token signing key, with claims (sub, email,
	// groups, etc.) carried in the bearer itself rather than looked up
	// from a token store.
	//
	// Unlike TokenSourceSSO, the JWT was minted by this server, not by an
	// upstream IdP — its signature verifies against this server's published
	// JWKS. Unlike TokenSourceOAuth, there is no entry in the TokenStore
	// keyed by the bearer (the bearer is not a database key).
	//
	// Downstream consumers must NOT pass a TokenSourceJWT bearer to a
	// resource server that expects an upstream-IdP-signed id_token (e.g.
	// the Kubernetes API authenticated against the upstream OIDC issuer).
	// For those flows, fetch the upstream id_token by another path (e.g.
	// the configured TokenRefreshHandler cache).
	TokenSourceJWT TokenSource = "jwt"
)

type UserInfo

type UserInfo struct {
	// ID is the unique user identifier from the provider
	ID string

	// Email is the user's email address
	Email string

	// EmailVerified indicates if the email is verified
	EmailVerified bool

	// Name is the user's full name
	Name string

	// GivenName is the user's first name
	GivenName string

	// FamilyName is the user's last name
	FamilyName string

	// Picture is the URL of the user's profile picture
	Picture string

	// Locale is the user's preferred locale
	Locale string

	// Groups contains group memberships from the identity provider.
	// This is populated from the 'groups' claim in OIDC userinfo responses.
	// Providers that don't support groups will leave this empty.
	Groups []string

	// TokenSource indicates how this user was authenticated.
	// This is set to TokenSourceOAuth for normal OAuth flow tokens
	// (where the ID token is stored in the token store) or TokenSourceSSO
	// for SSO-forwarded tokens (where the Bearer token IS the ID token).
	//
	// Downstream servers can use this to determine whether to look up
	// a stored ID token or use the Bearer token directly for downstream
	// authentication (e.g., Kubernetes API authentication).
	//
	// SECURITY: This field is set server-side during token validation and
	// should NOT be trusted if received from external sources (e.g., if
	// UserInfo is deserialized from untrusted input). Always use the server's
	// ValidateToken() method to obtain a trusted UserInfo with correct TokenSource.
	TokenSource TokenSource
}

UserInfo represents user information from a provider

func (*UserInfo) IsJWT added in v0.2.120

func (u *UserInfo) IsJWT() bool

IsJWT returns true if this user was authenticated via a self-issued JWT access token (RFC 9068). When true, the Bearer is a JWT signed by this server's own access-token signing key — not the upstream IdP's — and there is no entry in the TokenStore keyed by the bearer.

Returns false for nil receivers, OAuth tokens, SSO tokens, empty TokenSource, and unknown/invalid TokenSource values.

Downstream consumers MUST NOT pass a TokenSourceJWT bearer to resource servers expecting an upstream-IdP-signed id_token (e.g. Kubernetes authenticated against the upstream OIDC issuer). The JWT is signed by this OAuth server, not the upstream.

func (*UserInfo) IsOAuth added in v0.2.43

func (u *UserInfo) IsOAuth() bool

IsOAuth returns true if this user was authenticated via normal OAuth flow. When true, the server issued the token and the provider's ID token is stored in the token store.

Returns true for nil receivers (safe default) and empty TokenSource (backward compatibility with existing code). Returns false for SSO tokens and unknown/invalid TokenSource values.

Downstream servers should look up the stored ID token from the token store when this returns true.

func (*UserInfo) IsSSO added in v0.2.43

func (u *UserInfo) IsSSO() bool

IsSSO returns true if this user was authenticated via SSO token forwarding. When true, the Bearer token IS the ID token and there is no entry in the token store (the server didn't issue the token).

Returns false for nil receivers, OAuth tokens, empty TokenSource, and unknown/invalid TokenSource values.

Downstream servers should use the Bearer token directly for downstream authentication when this returns true, rather than looking up a stored token.

Directories

Path Synopsis
Package dex implements the OAuth provider interface for Dex (https://dexidp.io/).
Package dex implements the OAuth provider interface for Dex (https://dexidp.io/).
Package github implements the OAuth provider interface for GitHub OAuth Apps.
Package github implements the OAuth provider interface for GitHub OAuth Apps.
Package google provides a Google OAuth 2.0 provider implementation.
Package google provides a Google OAuth 2.0 provider implementation.
Package mock provides mock implementations of the Provider interface for testing purposes.
Package mock provides mock implementations of the Provider interface for testing purposes.
Package oidc provides shared OpenID Connect client utilities for OAuth providers.
Package oidc provides shared OpenID Connect client utilities for OAuth providers.

Jump to

Keyboard shortcuts

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