oauth

package
v0.5.4 Latest Latest
Warning

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

Go to latest
Published: May 6, 2026 License: MIT Imports: 20 Imported by: 0

README

OAuth

Last verified: 2026-05-02

The oauth package owns the OAuth 2.1 provider, token handlers, bearer context, and the production consent-helper surface used by browser authorization flows.

Replacing The Demo Authorize Handler

Provider.AuthorizeHandler is intentionally small and demo-oriented. Production servers should mount consent.NewHandler:

authorize, err := consent.NewHandler(consent.Config{
    Provider:       oauthProv,
    Authenticator:  myapp.NewAuthenticator(db),
    Renderer:       myapp.NewConsentRenderer(),
    PublicURL:      "https://my-mcp.example.com",
    ApprovalSecret: myapp.OAuthApprovalSecret(), // exactly 32 bytes
    AuditEmitter:   myapp.NewAuditEmitter(db),
})
if err != nil {
    return err
}
mux.Handle("/oauth/authorize", authorize)

The handler owns protocol mechanics: canonical POST-to-fosite request rebuilding, RFC 8707 strict-when-present resource validation, server-side audience binding, single-use approval tokens, and oauth.consent.approved / oauth.consent.denied audit events.

Collaborators

  • Authenticator checks credentials and returns oauth.Subject. Use Subject.Extra for consumer-specific claim data such as role or organization.
  • Renderer writes the login, consent, and redirect-bridge pages. It must include PageData.HiddenInputs in forms.
  • ApprovalTokenStore binds a successful login to one authorize request. Use hmacstore for stateless flows, or sessionstore when you already have a shared session backend.
  • ConsentPolicy gates scopes and can skip consent for trusted first-party clients.
  • ChallengeProvider is defined for future second-factor flows; no stock implementation ships yet.

Approval Token Backends

hmacstore.New(secret, time.Now) signs an opaque token and tracks replay in memory. It is the best default for single-process deployments. The map is bounded by approval-token TTL times abandoned login rate; wrap it with your own janitor if adversarial mint-but-never-consume behavior is realistic.

sessionstore.New(backend, time.Now) stores an opaque token in a consumer backend. SessionBackend.Pull must atomically delete and return the entry, or replay protection is broken.

Audit

Approve and deny paths emit:

  • EntityType: oauth_authorize
  • Action: oauth.consent.approved or oauth.consent.denied
  • ClientID, Scope, and metadata for client_name, decision, ip, user_agent, and resources

Audit emission is best-effort. Wrap your emitter if consent decisions must be durably queued before authorize completes.

Testing

Use oauth/consent/consenttest to construct an in-memory provider, register a PKCE client, and run the canonical handler suite:

consenttest.RunCanonicalSuite(t, handler, consenttest.SuiteOptions{
    Renderer:        renderer,
    AuthorizeValues: values,
})

Documentation

Index

Constants

View Source
const (

	// AuthSourceOAuth2 indicates a Fosite-issued bearer token authenticated the request.
	AuthSourceOAuth2 = "oauth2"
	// AuthSourcePAT indicates a personal access token authenticated the request.
	AuthSourcePAT = "pat"
)
View Source
const DefaultBcryptCost = 12

DefaultBcryptCost is the bcrypt work factor used for new hashes.

Variables

This section is empty.

Functions

func AuthorizationServerMetadataHandler added in v0.4.0

func AuthorizationServerMetadataHandler(cfg AuthorizationServerMetadataConfig) http.Handler

AuthorizationServerMetadataHandler returns OAuth authorization server metadata.

func Bearer

func Bearer(cfg BearerConfig) func(http.Handler) http.Handler

Bearer validates OAuth bearer tokens and optional PATs.

func ClassifyLoginError

func ClassifyLoginError(err error) string

ClassifyLoginError reduces authentication failures to a fixed vocabulary.

func ClassifyResetError

func ClassifyResetError(err error) string

ClassifyResetError reduces password-reset failures to a fixed vocabulary.

func ClassifySignupError

func ClassifySignupError(err error) string

ClassifySignupError reduces registration failures to a fixed vocabulary.

func ClassifyVerifyError

func ClassifyVerifyError(err error) string

ClassifyVerifyError reduces email-verification failures to a fixed vocabulary.

func GetAuthSource

func GetAuthSource(ctx context.Context) string

GetAuthSource returns the auth mechanism that authenticated the request.

func GetScopeTarget

func GetScopeTarget(ctx context.Context) string

GetScopeTarget returns the PAT scope target, when present.

func GetScopeType

func GetScopeType(ctx context.Context) string

GetScopeType returns the PAT scope type, when present.

func GetScopes

func GetScopes(ctx context.Context) fosite.Arguments

GetScopes returns granted scopes.

func GetUserID

func GetUserID(ctx context.Context) string

GetUserID returns the authenticated subject.

func HashPassword

func HashPassword(password string) (string, error)

HashPassword returns a bcrypt hash of password.

func HashSecret

func HashSecret(secret string) (string, error)

HashSecret returns a bcrypt hash of secret.

func IsAuthDisabled

func IsAuthDisabled(ctx context.Context) bool

IsAuthDisabled reports whether auth is disabled for this request.

func NeedsRehash

func NeedsRehash(hash string) bool

NeedsRehash reports whether hash was produced below DefaultBcryptCost.

func NewEmptySession

func NewEmptySession() *openid.DefaultSession

NewEmptySession creates an empty session for token exchange deserialization.

func NewRegistrationHandler added in v0.4.0

func NewRegistrationHandler(cfg RegistrationConfig) http.Handler

NewRegistrationHandler creates an RFC 7591 dynamic client registration handler.

func NewSession

func NewSession(subject Subject) *openid.DefaultSession

NewSession creates an OIDC session for subject.

func PKCEChallenge

func PKCEChallenge(verifier string) string

PKCEChallenge returns the RFC 7636 S256 challenge for verifier.

func ProtectedResourceMetadataHandler added in v0.4.0

func ProtectedResourceMetadataHandler(cfg ProtectedResourceMetadataConfig) http.Handler

ProtectedResourceMetadataHandler returns an RFC 9728 metadata handler.

func RandomState

func RandomState() (string, error)

RandomState returns a URL-safe random OAuth state parameter.

func RequireScope

func RequireScope(scope string) func(http.Handler) http.Handler

RequireScope denies requests that lack scope.

func RequireScopeForTarget

func RequireScopeForTarget(scope string, resolve TargetResolver) func(http.Handler) http.Handler

RequireScopeForTarget denies requests that lack scope or whose PAT boundary does not cover the resolved target. OAuth bearer tokens are checked by scope only; PATs with an empty boundary are treated as full access.

func VerifyPassword

func VerifyPassword(hash string, password string) error

VerifyPassword reports whether password matches hash.

func VerifySecret

func VerifySecret(hash string, secret string) error

VerifySecret reports whether secret matches hash.

func WithAuthDisabled

func WithAuthDisabled(ctx context.Context) context.Context

WithAuthDisabled marks a request as intentionally unauthenticated because auth is disabled.

func WithScopes

func WithScopes(ctx context.Context, scopes fosite.Arguments) context.Context

WithScopes stores granted scopes in context.

Types

type AuthorizationServerMetadataConfig added in v0.4.0

type AuthorizationServerMetadataConfig struct {
	Issuer                string
	AuthorizationEndpoint string
	TokenEndpoint         string
	RegistrationEndpoint  string
	ScopesSupported       []string
}

AuthorizationServerMetadataConfig configures OAuth authorization server metadata.

type BearerConfig

type BearerConfig struct {
	Introspector         TokenIntrospector
	SessionFactory       func() fosite.Session
	ResourceMetadataURL  string
	TokenValidator       TokenValidator
	Now                  func() time.Time
	RecordUsageTimeout   time.Duration
	MaxUsageRecorders    int
	AllowUnauthenticated bool
	ExpectedAudience     string
}

BearerConfig configures Bearer middleware.

type ClientRegistrar added in v0.4.0

type ClientRegistrar interface {
	SaveClient(context.Context, storage.Client) error
}

ClientRegistrar persists dynamically registered OAuth clients.

type Config

type Config struct {
	Secret   []byte //nolint:gosec // OAuth HMAC secret supplied by the consumer.
	Issuer   string
	Audience string
	Store    storage.Store

	KeyManager *keys.Manager

	AllowedScopes []string
	DefaultScopes []string

	AccessTokenLifespan   time.Duration
	RefreshTokenLifespan  time.Duration
	AuthorizeCodeLifespan time.Duration
	IDTokenLifespan       time.Duration
}

Config holds settings for the OAuth/OIDC provider.

type PATAuthResult

type PATAuthResult struct {
	UserID      string
	TokenID     string
	ScopeType   string
	ScopeTarget string
	Scopes      []string
}

PATAuthResult contains the identity and scopes resolved from a PAT.

type PATEntity

type PATEntity interface {
	GetID() string
	GetUserID() string
	GetScopes() []string
}

PATEntity is the minimum resolved PAT shape needed for authentication.

type PATValidator

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

PATValidator adapts a PATServicer to Bearer middleware.

func NewPATValidator

func NewPATValidator(service Servicer) *PATValidator

NewPATValidator creates a PAT validator.

func (*PATValidator) RecordUsage

func (v *PATValidator) RecordUsage(ctx context.Context, tokenID string)

RecordUsage updates last_used_at. Bearer calls this asynchronously.

func (*PATValidator) ValidateAndResolve

func (v *PATValidator) ValidateAndResolve(ctx context.Context, rawToken string) (*PATAuthResult, error)

ValidateAndResolve validates a raw PAT and resolves its scope restriction.

type PKCEPair

type PKCEPair struct {
	Verifier  string
	Challenge string
	Method    string
}

PKCEPair is a freshly generated PKCE verifier + challenge pair.

func NewPKCEPair

func NewPKCEPair() (PKCEPair, error)

NewPKCEPair generates an RFC 7636 S256 verifier/challenge pair.

type ProtectedResourceMetadataConfig added in v0.4.0

type ProtectedResourceMetadataConfig struct {
	Resource             string
	AuthorizationServers []string
	ScopesSupported      []string
}

ProtectedResourceMetadataConfig configures RFC 9728 protected resource metadata.

type Provider

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

Provider owns OAuth provider state and HTTP handlers.

func New

func New(cfg Config) (*Provider, error)

New constructs an OAuth provider backed by Fosite.

func (*Provider) AuthorizeHandler

func (p *Provider) AuthorizeHandler(resolve SubjectResolver) http.Handler

AuthorizeHandler returns an OAuth authorization endpoint that grants requested scopes immediately to whatever SubjectResolver returns.

This is a demo handler. It does not authenticate the browser session, does not collect explicit user consent, and does not bind the canonical resource audience server-side per RFC 8707. Production servers should replace it with oauth/consent.NewHandler.

func (*Provider) OAuth2Provider

func (p *Provider) OAuth2Provider() fosite.OAuth2Provider

OAuth2Provider exposes the underlying Fosite provider for advanced consumers.

func (*Provider) RegisterHandler

func (p *Provider) RegisterHandler() http.Handler

RegisterHandler returns the dynamic client registration handler.

func (*Provider) RegisterRoutes

func (p *Provider) RegisterRoutes(mux *http.ServeMux, prefix string, resolve SubjectResolver)

RegisterRoutes mounts OAuth handlers on mux with prefix, for example prefix "/oauth" mounts "/oauth/authorize", "/oauth/token", "/oauth/revoke", and "/oauth/register".

func (*Provider) RevokeHandler

func (p *Provider) RevokeHandler() http.Handler

RevokeHandler returns the OAuth token revocation endpoint.

func (*Provider) TokenHandler

func (p *Provider) TokenHandler() http.Handler

TokenHandler returns the OAuth token endpoint.

type RegistrationConfig added in v0.4.0

type RegistrationConfig struct {
	Store                          ClientRegistrar
	AllowedScopes                  []string
	DefaultScopes                  []string
	Audience                       string
	DefaultTokenEndpointAuthMethod string
	DefaultGrantTypes              []string
	DefaultResponseTypes           []string
	ClientIDPrefix                 string
}

RegistrationConfig configures a dynamic client registration handler.

type RegistrationHandler

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

RegistrationHandler implements RFC 7591 dynamic client registration.

func (*RegistrationHandler) ServeHTTP

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

type Servicer

type Servicer interface {
	ValidateToken(ctx context.Context, rawToken string) (PATEntity, error)
	GetTokenScope(ctx context.Context, tokenID string) (scopeType string, scopeTarget string, err error)
	UpdateLastUsed(ctx context.Context, tokenID string) error
}

Servicer is the consumer-owned persistence/service boundary for PATs.

type Subject

type Subject struct {
	ID            string
	Email         string
	GrantedScopes []string

	// Extra carries consumer-specific session data. Values are copied into
	// OIDC token claims as-is, so callers should use JSON-serializable values.
	Extra map[string]any
}

Subject is the authenticated resource owner authorizing an OAuth client.

type SubjectResolver

type SubjectResolver func(r *http.Request) (Subject, error)

SubjectResolver returns the authenticated subject for an authorize request.

type Target

type Target struct {
	ScopeType string
	Target    string
}

Target identifies a consumer resource protected by a target-scoped PAT.

type TargetResolver

type TargetResolver func(r *http.Request) (Target, error)

TargetResolver resolves the target resource for the current request.

type TokenIntrospector

type TokenIntrospector interface {
	IntrospectToken(context.Context, string, fosite.TokenType, fosite.Session, ...string) (
		fosite.TokenType,
		fosite.AccessRequester,
		error,
	)
}

TokenIntrospector validates OAuth bearer tokens. Fosite providers implement this interface.

type TokenValidator

type TokenValidator interface {
	ValidateAndResolve(ctx context.Context, rawToken string) (*PATAuthResult, error)
	RecordUsage(ctx context.Context, tokenID string)
}

TokenValidator validates personal access tokens.

Directories

Path Synopsis
Package consent provides one shared OAuth 2.1 authorization-endpoint handler that performs browser-based login, optional 2FA challenge, explicit user consent, and produces a fosite authorization response with the canonical MCP audience bound server-side per RFC 8707.
Package consent provides one shared OAuth 2.1 authorization-endpoint handler that performs browser-based login, optional 2FA challenge, explicit user consent, and produces a fosite authorization response with the canonical MCP audience bound server-side per RFC 8707.
consenttest
Package consenttest provides test fixtures for consent.Handler consumers.
Package consenttest provides test fixtures for consent.Handler consumers.
hmacstore
Package hmacstore implements consent.ApprovalTokenStore using a stateless HMAC-signed payload plus an in-memory replay map.
Package hmacstore implements consent.ApprovalTokenStore using a stateless HMAC-signed payload plus an in-memory replay map.
sessionstore
Package sessionstore implements consent.ApprovalTokenStore using a consumer-supplied session backend.
Package sessionstore implements consent.ApprovalTokenStore using a consumer-supplied session backend.
Package keys manages OAuth JWT signing keys.
Package keys manages OAuth JWT signing keys.
Package storage adapts consumer persistence to Fosite's OAuth storage interfaces.
Package storage adapts consumer persistence to Fosite's OAuth storage interfaces.

Jump to

Keyboard shortcuts

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