oauth

package
v0.2.0 Latest Latest
Warning

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

Go to latest
Published: Aug 14, 2026 License: Apache-2.0 Imports: 22 Imported by: 0

Documentation

Overview

Package oauth contains provider-neutral OAuth acquisition mechanics.

Provider packages provide a reviewed Definition: this package never chooses provider endpoints, client identities, scopes, or browser behavior for callers. It only validates and applies the definition's explicit policy.

Index

Constants

View Source
const (
	MaxVerifierLength         = 128
	MinVerifierLength         = 43
	MaxStateLength            = 128
	MaxCallbackValueLength    = 2048
	MaxTokenValueLength       = 16384
	MaxScopeLength            = 256
	MaxScopes                 = 128
	MaxExtraParams            = 64
	MaxRequestBodyBytes       = 64 << 10
	MaxResponseBodyBytes      = 256 << 10
	MaxRequestHeaders         = 64
	MaxResponseHeaders        = 128
	MaxHeaderBytes            = 32 << 10
	MaxPollAttempts           = 60
	MaxPollInterval           = 5 * time.Minute
	DefaultPollInterval       = 5 * time.Second
	MaxTokenLifetime          = 365 * 24 * time.Hour
	CallbackReadHeaderTimeout = 5 * time.Second
	CallbackIdleTimeout       = 30 * time.Second
)

Limits are deliberately conservative. OAuth providers should exchange bounded form and JSON messages; unbounded provider output must never enter memory or an error value.

Variables

View Source
var (
	ErrInvalidDefinition       = errors.New("oauth: invalid provider definition")
	ErrInvalidEndpoint         = errors.New("oauth: invalid endpoint")
	ErrOriginMismatch          = errors.New("oauth: endpoint origin is not pinned")
	ErrRedirectRejected        = errors.New("oauth: redirect rejected")
	ErrUnsupportedGrant        = errors.New("oauth: grant is not allowed")
	ErrInvalidClient           = errors.New("oauth: invalid sanctioned client")
	ErrInvalidRequest          = errors.New("oauth: invalid request")
	ErrInvalidResponse         = errors.New("oauth: invalid provider response")
	ErrResponseTooLarge        = errors.New("oauth: provider response too large")
	ErrResponseHeadersTooLarge = errors.New("oauth: provider response headers too large")
	ErrRequestTooLarge         = errors.New("oauth: provider request too large")
	ErrRequestHeadersTooLarge  = errors.New("oauth: provider request headers too large")
	ErrProvider                = errors.New("oauth: provider rejected request")
	ErrNetwork                 = errors.New("oauth: provider request failed")
	ErrCanceled                = credentials.ErrCanceled
	ErrNilContext              = credentials.ErrNilContext
	ErrStateMismatch           = errors.New("oauth: callback state mismatch")
	ErrStateUsed               = errors.New("oauth: callback state already used")
	ErrCallbackOrigin          = errors.New("oauth: callback origin rejected")
	ErrCallbackClosed          = errors.New("oauth: callback listener closed")
	ErrCallbackTimeout         = errors.New("oauth: callback wait timed out")
	ErrPollLimit               = errors.New("oauth: device polling limit reached")
	ErrDeviceExpired           = errors.New("oauth: device authorization expired")
	ErrRevocationUnsupported   = errors.New("oauth: revocation endpoint unavailable")
)
View Source
var ErrInvalidVerifier = errors.New("oauth: invalid PKCE verifier")

Functions

func GenerateState

func GenerateState() (string, error)

GenerateState is an explicit alias for NewState.

func GenerateVerifier

func GenerateVerifier() (string, error)

GenerateVerifier is an explicit alias for NewVerifier.

func IsProviderError

func IsProviderError(err error) bool

NewProviderError is intentionally not exported with a body/code argument; provider errors are only created from bounded protocol classification.

func NewState

func NewState() (string, error)

NewState returns a cryptographically random, bounded callback state.

func NewVerifier

func NewVerifier() (string, error)

NewVerifier returns a RFC 7636 verifier with 32 random bytes encoded using unpadded base64url (43 characters).

func ParseExpiresIn

func ParseExpiresIn(value string) (int64, error)

ParseExpiresIn accepts provider values represented as JSON numbers or bounded decimal strings for provider parsers that need this helper.

func S256

func S256(verifier string) (string, error)

S256 is a concise alias for S256Challenge.

func S256Challenge

func S256Challenge(verifier string) (string, error)

S256Challenge derives the unpadded base64url SHA-256 challenge for a valid verifier. It does not retain the verifier or include it in an error.

func ValidateState

func ValidateState(expected, received string) error

ValidateState compares callback state using constant-time equality and never returns either value in an error.

func ValidateVerifier

func ValidateVerifier(verifier string) error

ValidateVerifier checks RFC 7636's length and unreserved-byte grammar.

Types

type AuthorizationFlow

type AuthorizationFlow struct {
	URL       string
	State     string
	Verifier  string
	Challenge string
	Callback  CallbackInstructions
	// contains filtered or unexported fields
}

AuthorizationFlow is the stateful authorization-code initiation result. State/verifier are returned so a caller can persist an encrypted operation state if needed; String and formatting methods never reveal them.

func BeginAuthorization

func BeginAuthorization(ctx context.Context, definition Definition, options ...Option) (*AuthorizationFlow, error)

BeginAuthorization starts an authorization-code + PKCE operation. It binds a random loopback path and returns instructions; no browser is opened.

func BeginAuthorizationCode

func BeginAuthorizationCode(ctx context.Context, definition Definition, options ...Option) (*AuthorizationFlow, error)

BeginAuthorizationCode is an explicit alias for BeginAuthorization.

func (*AuthorizationFlow) Close

func (f *AuthorizationFlow) Close() error

Close stops the callback listener. It is idempotent and does not close an injected HTTP client.

func (*AuthorizationFlow) Exchange

func (f *AuthorizationFlow) Exchange(ctx context.Context, result CallbackResult, options ...Option) (TokenResponse, error)

Exchange consumes the callback code and performs a PKCE token exchange.

func (AuthorizationFlow) Format

func (f AuthorizationFlow) Format(state fmt.State, _ rune)

func (AuthorizationFlow) LogValue

func (f AuthorizationFlow) LogValue() slog.Value

func (AuthorizationFlow) String

func (f AuthorizationFlow) String() string

func (*AuthorizationFlow) Wait

Wait consumes the one accepted callback invocation.

type CallbackInstructions

type CallbackInstructions struct {
	URL         string
	RedirectURI string
	Path        string
	Method      string
}

CallbackInstructions tell the product exactly where and how to receive the provider redirect. The product decides whether to open the authorization URL.

func (CallbackInstructions) Format

func (i CallbackInstructions) Format(state fmt.State, _ rune)

func (CallbackInstructions) GoString

func (i CallbackInstructions) GoString() string

func (CallbackInstructions) LogValue

func (i CallbackInstructions) LogValue() slog.Value

func (CallbackInstructions) String

func (i CallbackInstructions) String() string

type CallbackResult

type CallbackResult struct {
	Code      string
	State     string
	ErrorCode string
}

CallbackResult is the one accepted callback. Code and error code are returned to the operation owner but deliberately redacted by formatting.

func ParseCallbackQuery

func ParseCallbackQuery(query url.Values, expectedState string) (CallbackResult, error)

ParseCallbackQuery parses manually collected callback query parameters.

func ParseCallbackURL

func ParseCallbackURL(raw, expectedState string, exactPath ...string) (CallbackResult, error)

ParseCallbackURL is the explicit manual callback seam. It accepts only a loopback HTTP URL, requires an exact state, and never includes callback values in its errors.

func ParseCallbackURLForInstructions

func ParseCallbackURLForInstructions(raw, expectedState string, instructions CallbackInstructions) (CallbackResult, error)

ParseCallbackURLForInstructions parses only the authority issued by a listener. It is the safe manual-completion API; the legacy parser above is retained only for callers that do not have an issued listener.

func (CallbackResult) CallbackError

func (r CallbackResult) CallbackError() error

CallbackError returns a safe classified error for provider-declined callbacks. It never exposes ErrorCode or a provider description.

func (CallbackResult) Format

func (r CallbackResult) Format(state fmt.State, _ rune)

func (CallbackResult) GoString

func (r CallbackResult) GoString() string

func (CallbackResult) HasError

func (r CallbackResult) HasError() bool

func (CallbackResult) LogValue

func (r CallbackResult) LogValue() slog.Value

func (CallbackResult) String

func (r CallbackResult) String() string

type ClientIdentity

type ClientIdentity = ClientRegistration

ClientIdentity is an alias used by integrations that name this policy object explicitly.

type ClientRegistration

type ClientRegistration struct {
	// ClientID is the canonical sanctioned public-client identity. ID is a
	// compatibility spelling and must mirror ClientID when supplied.
	ClientID            string
	ID                  string
	RedirectURIs        []string
	AllowedRedirectURIs []string
	AllowedOrigins      []string
	AllowedGrants       []Grant
	Scopes              []string
	LoopbackRedirect    LoopbackRedirectPolicy
	Sanctioned          bool
	Evidence            string
}

ClientRegistration is the provider-reviewed OAuth client identity. It has no client secret: PKCE/device mechanics are intended for public clients.

type Config

type Config = Definition

type Definition

type Definition struct {
	AuthorizationEndpoint       string
	TokenEndpoint               string
	DeviceAuthorizationEndpoint string
	RevocationEndpoint          string

	// URL aliases are accepted for provider packages that use URL terminology.
	AuthorizationURL       string
	TokenURL               string
	DeviceAuthorizationURL string
	DeviceURL              string
	RevocationURL          string

	ClientID               string
	SanctionedClientID     string
	Client                 ClientRegistration
	Registration           ClientRegistration
	AllowedOrigins         []string
	Origins                []string
	AllowedEndpointOrigins []string
	AllowedGrants          []Grant
	Grants                 []Grant
	Scopes                 []string
	ExtraParams            map[string]string
	AuthorizationParams    map[string]string
	DeviceParams           map[string]string
	TokenParams            map[string]string
	Parser                 ResponseParser

	// Provider parsers are deliberately byte-oriented so provider packages can
	// interpret a bounded response without this package knowing account fields.
	TokenParser         func([]byte) (TokenResponse, error)
	DeviceParser        func([]byte) (DeviceAuthorization, error)
	ParseTokenResponse  func([]byte) (TokenResponse, error)
	ParseDeviceResponse func([]byte) (DeviceAuthorization, error)
}

Definition is an explicit, provider-supplied OAuth policy. Endpoint values are exact HTTPS URLs; AllowedOrigins pins all network requests to reviewed origins. No endpoint or client identity is inferred from provider names.

func (Definition) BeginAuthorization

func (d Definition) BeginAuthorization(ctx context.Context, options ...Option) (*AuthorizationFlow, error)

BeginAuthorization starts the same operation as the package function.

func (Definition) ExchangeCode

func (d Definition) ExchangeCode(ctx context.Context, code, verifier, redirectURI string, options ...Option) (TokenResponse, error)

ExchangeCode exchanges one callback code with PKCE. Code and verifier are validated before network use and are never retained in returned errors.

func (Definition) Format

func (d Definition) Format(state fmt.State, _ rune)

func (Definition) GoString

func (d Definition) GoString() string

func (Definition) LogValue

func (d Definition) LogValue() slog.Value

func (Definition) PollDevice

func (d Definition) PollDevice(ctx context.Context, device DeviceAuthorization, options ...Option) (TokenResponse, error)

PollDevice polls the token endpoint according to RFC 8628. A provider's authorization_pending and slow_down classifications are retained only as closed protocol classes; provider response bodies never enter errors.

func (Definition) RefreshToken

func (d Definition) RefreshToken(ctx context.Context, refreshToken string, previous TokenResponse, options ...Option) (TokenResponse, error)

RefreshToken exchanges one refresh token and applies rotation semantics.

func (Definition) RevokeToken

func (d Definition) RevokeToken(ctx context.Context, token string, options ...Option) error

RevokeToken performs an explicit token revocation when the provider definition reviewed a revocation endpoint. It returns no provider body.

func (Definition) SortOrigins

func (d Definition) SortOrigins() []string

SortOrigins returns a stable copy useful to provider registration tests.

func (Definition) StartDeviceAuthorization

func (d Definition) StartDeviceAuthorization(ctx context.Context, options ...Option) (DeviceAuthorization, error)

StartDeviceAuthorization obtains one bounded device code. It does not open a browser or print a user code.

func (Definition) StartDeviceFlow

func (d Definition) StartDeviceFlow(ctx context.Context, options ...Option) (*DeviceFlow, error)

StartDeviceFlow is a convenience wrapper around StartDeviceAuthorization.

func (Definition) String

func (d Definition) String() string

func (Definition) Validate

func (d Definition) Validate() error

Validate verifies the complete safe definition. It intentionally does not retain or report invalid endpoint/client strings.

type DeviceAuthorization

type DeviceAuthorization struct {
	DeviceCode              string
	UserCode                string
	VerificationURI         string
	VerificationURIComplete string
	ExpiresIn               int64
	Interval                int
	ExpiresAt               time.Time
}

DeviceAuthorization is the bounded device authorization response. Device and user codes are returned to the caller but never formatted in errors.

func DeviceAuthorizationRequest

func DeviceAuthorizationRequest(ctx context.Context, definition Definition, options ...Option) (DeviceAuthorization, error)

DeviceAuthorizationRequest is an explicit alias for starting a device authorization request.

func ParseDeviceAuthorizationResponse

func ParseDeviceAuthorizationResponse(body []byte) (DeviceAuthorization, error)

ParseDeviceAuthorizationResponse parses the standard RFC 8628 response.

func (DeviceAuthorization) Format

func (d DeviceAuthorization) Format(state fmt.State, _ rune)

func (DeviceAuthorization) GoString

func (d DeviceAuthorization) GoString() string

func (DeviceAuthorization) LogValue

func (d DeviceAuthorization) LogValue() slog.Value

func (DeviceAuthorization) String

func (d DeviceAuthorization) String() string

func (DeviceAuthorization) Valid

func (d DeviceAuthorization) Valid() bool

type DeviceAuthorizationResponse

type DeviceAuthorizationResponse = DeviceAuthorization

DeviceAuthorizationResponse is a descriptive alias.

type DeviceFlow

type DeviceFlow struct {
	Definition Definition
	Device     DeviceAuthorization
}

DeviceFlow packages a device response and its explicit definition.

func (*DeviceFlow) Poll

func (f *DeviceFlow) Poll(ctx context.Context, options ...Option) (TokenResponse, error)

Poll waits for user completion with bounded, cancellation-aware polling.

type Grant

type Grant string

Grant is an OAuth grant identifier. Definitions must explicitly allow every grant a caller requests.

const (
	GrantAuthorizationCode   Grant = "authorization_code"
	GrantDeviceCode          Grant = "urn:ietf:params:oauth:grant-type:device_code"
	GrantDeviceAuthorization       = GrantDeviceCode
	GrantRefreshToken        Grant = "refresh_token"
)

type LoopbackListener

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

LoopbackListener accepts one exact GET + path + state callback. It binds only to IPv4 loopback and does not retain provider error descriptions.

func ListenLoopback

func ListenLoopback(ctx context.Context, options ...Option) (*LoopbackListener, error)

ListenLoopback creates a random exact callback path and state. BeginAuthorization uses the state-bearing internal constructor so the same state is included in its PKCE URL.

func NewLoopbackListener

func NewLoopbackListener(ctx context.Context, options ...Option) (*LoopbackListener, error)

NewLoopbackListener is an explicit constructor alias.

func (*LoopbackListener) Client

func (l *LoopbackListener) Client() *http.Client

Client returns a client suitable for calling the local callback endpoint. It follows no redirects and is independent from provider HTTP clients.

func (*LoopbackListener) Close

func (l *LoopbackListener) Close() error

Close closes the callback endpoint. It does not retain arbitrary server errors and is safe to call multiple times.

func (*LoopbackListener) Format

func (l *LoopbackListener) Format(state fmt.State, _ rune)

func (*LoopbackListener) GoString

func (l *LoopbackListener) GoString() string

func (*LoopbackListener) Instructions

func (l *LoopbackListener) Instructions() CallbackInstructions

Instructions returns the fixed callback binding.

func (*LoopbackListener) LogValue

func (l *LoopbackListener) LogValue() slog.Value

func (*LoopbackListener) ParseCallback

func (l *LoopbackListener) ParseCallback(raw string) (CallbackResult, error)

ParseCallback consumes a manually collected callback exactly once.

func (*LoopbackListener) ServeHTTP

func (l *LoopbackListener) ServeHTTP(response http.ResponseWriter, request *http.Request)

func (*LoopbackListener) State

func (l *LoopbackListener) State() string

State returns the operation's state to the owner of the listener.

func (*LoopbackListener) String

func (l *LoopbackListener) String() string

func (*LoopbackListener) Wait

Wait waits for the one accepted callback or context cancellation.

type LoopbackRedirectPolicy

type LoopbackRedirectPolicy struct {
	Enabled          bool
	Host             string
	Method           string
	PathPrefix       string
	AllowDynamicPort bool
}

LoopbackRedirectPolicy is the reviewed redirect contract for public authorization-code clients. The port is intentionally dynamic, while host, method, and random path prefix remain exact.

type Option

type Option func(*operationOptions)

Option configures one operation. Options are copied and never retained by a provider definition.

func WithHTTPClient

func WithHTTPClient(client *http.Client) Option

WithHTTPClient supplies a caller-owned client/transport. The client is shallow-copied and its redirect policy is replaced with the package's fail-closed policy; the caller's client is never mutated or closed.

func WithMaxPolls

func WithMaxPolls(attempts int) Option

WithMaxPolls bounds the number of device token requests.

func WithPollInterval

func WithPollInterval(interval time.Duration) Option

WithPollInterval controls device polling backoff for tests and callers with a provider-published interval. It is bounded by MaxPollInterval.

func WithPollSleeper

func WithPollSleeper(sleeper func(context.Context, time.Duration) error) Option

WithPollSleeper injects a context-aware sleeper. It is useful for tests and does not permit provider data to enter an error.

type PKCE

type PKCE struct {
	Verifier  string
	Challenge string
	State     string
}

PKCE contains one authorization-code operation's verifier, state, and S256 challenge. Values are URL-safe and generated from crypto/rand.

func NewPKCE

func NewPKCE() (PKCE, error)

NewPKCE creates independent verifier and state values and derives the RFC 7636 S256 challenge.

func (PKCE) Format

func (p PKCE) Format(state fmt.State, _ rune)

func (PKCE) GoString

func (p PKCE) GoString() string

func (PKCE) LogValue

func (p PKCE) LogValue() slog.Value

func (PKCE) String

func (p PKCE) String() string

type ProviderDefinition

type ProviderDefinition = Definition

ProviderDefinition and Config are compatibility aliases for the same provider-neutral policy object.

type ProviderError

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

ProviderError classifies a rejected request without retaining its body, description, headers, code, or request identifier.

func (*ProviderError) Code

func (e *ProviderError) Code() string

Code returns a tiny allowlisted protocol classification (never arbitrary provider text). It is intended only for polling state transitions.

func (*ProviderError) Error

func (e *ProviderError) Error() string

func (*ProviderError) Format

func (e *ProviderError) Format(state fmt.State, _ rune)

func (*ProviderError) GoString

func (e *ProviderError) GoString() string

func (*ProviderError) LogValue

func (e *ProviderError) LogValue() slog.Value

func (*ProviderError) StatusCode

func (e *ProviderError) StatusCode() int

func (*ProviderError) String

func (e *ProviderError) String() string

func (*ProviderError) Unwrap

func (e *ProviderError) Unwrap() error

type ResponseParser

type ResponseParser interface {
	ParseTokenResponse([]byte) (TokenResponse, error)
	ParseDeviceAuthorization([]byte) (DeviceAuthorization, error)
}

ResponseParser lets a provider package interpret bounded response bytes without making this package aware of account-specific fields.

type Revoker

type Revoker interface {
	RevokeToken(context.Context, string, ...Option) error
}

Revoker is the minimal provider-neutral revocation seam.

type StateGuard

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

StateGuard is a single-use state validator. A matching state can be consumed exactly once; mismatches do not consume it.

func NewStateGuard

func NewStateGuard(expected string) (*StateGuard, error)

NewStateGuard creates a one-use state guard.

func (*StateGuard) Consume

func (g *StateGuard) Consume(received string) error

Consume validates and atomically consumes one callback state.

func (StateGuard) Format

func (g StateGuard) Format(state fmt.State, _ rune)

func (StateGuard) GoString

func (g StateGuard) GoString() string

func (StateGuard) LogValue

func (g StateGuard) LogValue() slog.Value

func (*StateGuard) State

func (g *StateGuard) State() string

State returns the expected state only to the owner of a guard. It is safe metadata, but callers should still avoid logging it.

func (StateGuard) String

func (g StateGuard) String() string

type Token

type Token = TokenResponse

Token is an alias retained for provider code that calls a response a token.

type TokenResponse

type TokenResponse struct {
	AccessToken  string
	RefreshToken string
	TokenType    string
	Scope        string
	ExpiresIn    int64
	ExpiresAt    time.Time
}

TokenResponse is the bounded result of an OAuth token exchange. Token strings are retained here because the caller must persist/use them; all formatting and errors redact them.

func ExchangeAuthorizationCode

func ExchangeAuthorizationCode(ctx context.Context, definition Definition, code, verifier, redirectURI string, options ...Option) (TokenResponse, error)

ExchangeAuthorizationCode is a package-level convenience alias.

func ParseTokenResponse

func ParseTokenResponse(body []byte) (TokenResponse, error)

ParseTokenResponse parses the standard OAuth JSON response with strict size and field bounds. Caller-provided provider parsers are given the same already-bounded bytes by Definition.

func Poll

func Poll(ctx context.Context, definition Definition, device DeviceAuthorization, options ...Option) (TokenResponse, error)

Poll is a package-level convenience spelling.

func PollDeviceAuthorization

func PollDeviceAuthorization(ctx context.Context, definition Definition, device DeviceAuthorization, options ...Option) (TokenResponse, error)

PollDeviceAuthorization is a descriptive alias for Poll.

func RotateRefreshToken

func RotateRefreshToken(previous, next TokenResponse) TokenResponse

RotateRefreshToken applies OAuth refresh-token rotation. Providers may omit refresh_token when the prior token remains valid; in that case the old token is copied into the new immutable response. It never retains a provider error.

func (TokenResponse) Format

func (t TokenResponse) Format(state fmt.State, _ rune)

func (TokenResponse) GoString

func (t TokenResponse) GoString() string

func (TokenResponse) LogValue

func (t TokenResponse) LogValue() slog.Value

func (TokenResponse) Rotate

func (t TokenResponse) Rotate(previous TokenResponse) TokenResponse

Rotate is a method spelling of RotateRefreshToken.

func (TokenResponse) String

func (t TokenResponse) String() string

func (TokenResponse) Valid

func (t TokenResponse) Valid() bool

Jump to

Keyboard shortcuts

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