oauth

package
v0.14.0 Latest Latest
Warning

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

Go to latest
Published: Oct 11, 2026 License: MIT Imports: 24 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func AccessRequestFromContext

func AccessRequestFromContext(ctx context.Context) fosite.AccessRequester

AccessRequestFromContext extracts the access request from context.

func HasScope

func HasScope(ctx context.Context, scope string) bool

HasScope checks if the access request in context has a specific scope.

func LoggerFromContext

func LoggerFromContext(ctx context.Context) *slog.Logger

LoggerFromContext returns the logger from context, or slog.Default() if not set.

func ScopesFromContext

func ScopesFromContext(ctx context.Context) []string

ScopesFromContext extracts the granted scopes from the access request in context.

func UserIDFromContext

func UserIDFromContext(ctx context.Context) string

UserIDFromContext extracts the user ID (subject) from the access request in context.

func WithAccessRequest

func WithAccessRequest(ctx context.Context, ar fosite.AccessRequester) context.Context

WithAccessRequest adds the access request to the context.

Types

type API

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

API provides HTTP handlers for OAuth 2.0 endpoints using Huma/Chi. It uses a hybrid approach: discovery endpoints use Huma for full typed handling, while Fosite-integrated endpoints use Chi handlers directly.

func NewAPI

func NewAPI(provider *Provider, opts ...Option) (*API, error)

NewAPI creates a new OAuth API with Chi router and Huma.

func (*API) Huma

func (a *API) Huma() huma.API

Huma returns the underlying Huma API for advanced configuration.

func (*API) Logger

func (a *API) Logger() *slog.Logger

Logger returns the API's logger.

func (*API) Middleware

func (a *API) Middleware(next http.Handler) http.Handler

Middleware provides OAuth token validation middleware.

func (*API) Provider

func (a *API) Provider() *Provider

Provider returns the OAuth provider.

func (*API) Router

func (a *API) Router() chi.Router

Router returns the Chi router for mounting or serving.

func (*API) ServeHTTP

func (a *API) ServeHTTP(w http.ResponseWriter, r *http.Request)

ServeHTTP implements http.Handler.

type AuthorizeInput

type AuthorizeInput struct {
	ResponseType        string `query:"response_type" required:"true" enum:"code,token" doc:"OAuth 2.0 response type"`
	ClientID            string `query:"client_id" required:"true" doc:"Client identifier"`
	RedirectURI         string `query:"redirect_uri" doc:"URI to redirect after authorization"`
	Scope               string `query:"scope" doc:"Space-separated list of requested scopes"`
	State               string `query:"state" doc:"Opaque value for CSRF protection"`
	CodeChallenge       string `query:"code_challenge" doc:"PKCE code challenge"`
	CodeChallengeMethod string `query:"code_challenge_method" enum:"S256,plain" doc:"PKCE code challenge method"`
	Nonce               string `query:"nonce" doc:"OpenID Connect nonce for replay protection"`
}

AuthorizeInput represents the OAuth 2.0 authorization request parameters.

type AuthorizeOutput

type AuthorizeOutput struct {
	Location string `header:"Location" doc:"Redirect URI with authorization code or token"`
}

AuthorizeOutput represents the authorization response (redirect).

type Client

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

Client implements fosite.Client backed by Ent OAuthApp.

func (*Client) GetAudience

func (c *Client) GetAudience() fosite.Arguments

GetAudience returns the audience for this client.

func (*Client) GetGrantTypes

func (c *Client) GetGrantTypes() fosite.Arguments

GetGrantTypes returns the allowed grant types.

func (*Client) GetHashedSecret

func (c *Client) GetHashedSecret() []byte

GetHashedSecret returns nothing - we use custom validation.

func (*Client) GetID

func (c *Client) GetID() string

GetID returns the client ID.

func (*Client) GetRedirectURIs

func (c *Client) GetRedirectURIs() []string

GetRedirectURIs returns the registered redirect URIs.

func (*Client) GetResponseTypes

func (c *Client) GetResponseTypes() fosite.Arguments

GetResponseTypes returns the allowed response types.

func (*Client) GetScopes

func (c *Client) GetScopes() fosite.Arguments

GetScopes returns the allowed scopes.

func (*Client) IsPublic

func (c *Client) IsPublic() bool

IsPublic returns true if this is a public client (SPA, native app).

type Config

type Config struct {
	// Issuer is the OAuth/OIDC issuer URL
	Issuer string

	// AccessTokenLifespan is the duration access tokens are valid
	AccessTokenLifespan time.Duration

	// RefreshTokenLifespan is the duration refresh tokens are valid
	RefreshTokenLifespan time.Duration

	// AuthCodeLifespan is the duration authorization codes are valid
	AuthCodeLifespan time.Duration

	// PrivateKey is the RSA private key for signing tokens
	// If nil, a key will be generated
	PrivateKey *rsa.PrivateKey

	// HashSecret is the secret used for HMAC operations
	HashSecret []byte
}

Config holds OAuth 2.0 server configuration.

func DefaultConfig

func DefaultConfig(issuer string, hashSecret []byte) *Config

DefaultConfig returns a default OAuth configuration.

type ConsentFunc added in v0.14.0

type ConsentFunc func(ctx context.Context, userID string, client fosite.Client, scopes []string) (bool, error)

ConsentFunc reports whether userID has consented to client receiving scopes. It is consulted for clients that are not first-party.

type IntrospectInput

type IntrospectInput struct {
	Token         string `form:"token" required:"true" doc:"The token to introspect"`
	TokenTypeHint string `form:"token_type_hint" enum:"access_token,refresh_token" doc:"Hint about the token type"`

	// Client authentication
	Authorization string `header:"Authorization" doc:"Basic authentication header (client_id:client_secret)"`
}

IntrospectInput represents the token introspection request.

type IntrospectOutput

type IntrospectOutput struct {
	Body IntrospectResponse
}

IntrospectOutput wraps the introspection response.

type IntrospectResponse

type IntrospectResponse struct {
	Active    bool   `json:"active" doc:"Whether the token is active"`
	Scope     string `json:"scope,omitempty" doc:"Scopes associated with the token"`
	ClientID  string `json:"client_id,omitempty" doc:"Client that requested the token"`
	Username  string `json:"username,omitempty" doc:"Resource owner username"`
	TokenType string `json:"token_type,omitempty" doc:"Token type"`
	Exp       int64  `json:"exp,omitempty" doc:"Token expiration timestamp"`
	Iat       int64  `json:"iat,omitempty" doc:"Token issue timestamp"`
	Nbf       int64  `json:"nbf,omitempty" doc:"Token not-before timestamp"`
	Sub       string `json:"sub,omitempty" doc:"Subject (user ID)"`
	Aud       string `json:"aud,omitempty" doc:"Intended audience"`
	Iss       string `json:"iss,omitempty" doc:"Token issuer"`
	Jti       string `json:"jti,omitempty" doc:"JWT ID"`
}

IntrospectResponse represents the token introspection response.

type JWK

type JWK struct {
	Kty string `json:"kty" doc:"Key type (e.g., RSA, EC)"`
	Use string `json:"use,omitempty" doc:"Key use (sig for signature, enc for encryption)"`
	Kid string `json:"kid,omitempty" doc:"Key ID"`
	Alg string `json:"alg,omitempty" doc:"Algorithm"`
	N   string `json:"n,omitempty" doc:"RSA modulus"`
	E   string `json:"e,omitempty" doc:"RSA exponent"`
}

JWK represents a JSON Web Key.

type JWKS

type JWKS struct {
	Keys []JWK `json:"keys" doc:"Array of JSON Web Keys"`
}

JWKS represents a JSON Web Key Set.

type JWKSOutput

type JWKSOutput struct {
	Body JWKS
}

JWKSOutput is the response for the JWKS endpoint.

type OAuthError

type OAuthError struct {
	Error            string `json:"error" doc:"Error code"`
	ErrorDescription string `json:"error_description,omitempty" doc:"Human-readable error description"`
	ErrorURI         string `json:"error_uri,omitempty" doc:"URI with more information about the error"`
}

OAuthError represents an OAuth 2.0 error response.

type OpenIDConfigOutput

type OpenIDConfigOutput struct {
	Body OpenIDConfiguration
}

OpenIDConfigOutput is the response for the OpenID Configuration endpoint.

type OpenIDConfiguration

type OpenIDConfiguration struct {
	Issuer                            string   `json:"issuer" doc:"OAuth 2.0 Issuer Identifier"`
	AuthorizationEndpoint             string   `json:"authorization_endpoint" doc:"URL of the authorization endpoint"`
	TokenEndpoint                     string   `json:"token_endpoint" doc:"URL of the token endpoint"`
	IntrospectionEndpoint             string   `json:"introspection_endpoint" doc:"URL of the introspection endpoint"`
	RevocationEndpoint                string   `json:"revocation_endpoint" doc:"URL of the revocation endpoint"`
	JWKSURI                           string   `json:"jwks_uri" doc:"URL of the JSON Web Key Set document"`
	ResponseTypesSupported            []string `json:"response_types_supported" doc:"List of supported response types"`
	GrantTypesSupported               []string `json:"grant_types_supported" doc:"List of supported grant types"`
	TokenEndpointAuthMethodsSupported []string `json:"token_endpoint_auth_methods_supported" doc:"List of supported token endpoint authentication methods"`
	CodeChallengeMethodsSupported     []string `json:"code_challenge_methods_supported" doc:"List of supported PKCE code challenge methods"`
}

OpenIDConfiguration represents the OpenID Connect discovery document.

type Option

type Option func(*API)

Option configures an API.

func WithConsent added in v0.14.0

func WithConsent(consent ConsentFunc) Option

WithConsent sets how consent is checked for clients that are not first-party. Without it such clients are refused with access_denied; first-party clients never need consent.

func WithLogger

func WithLogger(logger *slog.Logger) Option

WithLogger sets the logger for the API. If not set, slog.Default() is used.

func WithLoginURL added in v0.14.0

func WithLoginURL(loginURL string) Option

WithLoginURL sets where unauthenticated users are sent; the original authorization request is passed back in the redirect query parameter. Without it, an unauthenticated authorization request is answered with login_required.

func WithTrustedUserIDHeader added in v0.14.0

func WithTrustedUserIDHeader(header string, gate systemauth.RequestGate) Option

WithTrustedUserIDHeader authenticates users from a header written by a gateway that has already authenticated them (a backend-for-frontend). Only requests the gate admits are believed; see systemauth.TrustedProxyNetworks and systemauth.TrustAllRequests. A nil gate or an empty header trusts nothing.

func WithUserAuthenticator added in v0.14.0

func WithUserAuthenticator(authenticate func(r *http.Request) string) Option

WithUserAuthenticator sets how the authorization endpoint learns who the user is: it returns the authenticated user's ID for the request, or "" when there is none, for example by validating a session cookie. Until one is set, the authorization endpoint refuses every request with server_error rather than guess.

type Provider

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

Provider wraps Fosite and provides OAuth 2.0/OIDC functionality.

func NewProvider

func NewProvider(db *ent.Client, cfg *Config) (*Provider, error)

NewProvider creates a new OAuth provider.

func (*Provider) OAuth2Provider

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

OAuth2Provider returns the underlying Fosite provider.

func (*Provider) Session

func (p *Provider) Session(subject string) *openid.DefaultSession

Session creates a new OAuth session for subject. The subject is set on the session itself, which Fosite reads for introspection and token storage, as well as on the ID token claims.

func (*Provider) Storage

func (p *Provider) Storage() *Storage

Storage returns the storage adapter.

type RevokeInput

type RevokeInput struct {
	Token         string `form:"token" required:"true" doc:"The token to revoke"`
	TokenTypeHint string `form:"token_type_hint" enum:"access_token,refresh_token" doc:"Hint about the token type"`

	// Client authentication
	Authorization string `header:"Authorization" doc:"Basic authentication header (client_id:client_secret)"`
}

RevokeInput represents the token revocation request.

type RevokeOutput

type RevokeOutput struct{}

RevokeOutput represents the token revocation response (empty on success).

type Storage

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

Storage implements the Fosite storage interfaces using Ent.

Clients are this package's Client. Authorization codes, tokens, PKCE, and revocation are delegated to SystemAuth's storage over the same tables, which stores each grant's full request and session, so a code exchange keeps the subject, the PKCE challenge, and the redirect URI it was issued with, and refresh-token reuse revokes the token family.

func NewStorage

func NewStorage(db *ent.Client) *Storage

NewStorage creates a new Fosite storage backed by Ent.

func (*Storage) ClientAssertionJWTValid added in v0.14.0

func (s *Storage) ClientAssertionJWTValid(ctx context.Context, jti string) error

ClientAssertionJWTValid reports fosite.ErrJTIKnown for a client-assertion JWT ID that is already used.

func (*Storage) CreateAccessTokenSession

func (s *Storage) CreateAccessTokenSession(ctx context.Context, signature string, request fosite.Requester) error

CreateAccessTokenSession stores an access token with its request.

func (*Storage) CreateAuthorizeCodeSession

func (s *Storage) CreateAuthorizeCodeSession(ctx context.Context, code string, request fosite.Requester) error

CreateAuthorizeCodeSession stores an authorization code with its request.

func (*Storage) CreatePKCERequestSession

func (s *Storage) CreatePKCERequestSession(ctx context.Context, signature string, request fosite.Requester) error

CreatePKCERequestSession records a code's PKCE challenge.

func (*Storage) CreateRefreshTokenSession

func (s *Storage) CreateRefreshTokenSession(ctx context.Context, signature string, accessSignature string, request fosite.Requester) error

CreateRefreshTokenSession stores a refresh token, on the paired access token's row when there is one.

func (*Storage) DeleteAccessTokenSession

func (s *Storage) DeleteAccessTokenSession(ctx context.Context, signature string) error

DeleteAccessTokenSession removes an access token session.

func (*Storage) DeletePKCERequestSession

func (s *Storage) DeletePKCERequestSession(ctx context.Context, signature string) error

DeletePKCERequestSession is a no-op: the challenge lives on the authorization code, which the code exchange invalidates.

func (*Storage) DeleteRefreshTokenSession

func (s *Storage) DeleteRefreshTokenSession(ctx context.Context, signature string) error

DeleteRefreshTokenSession revokes a refresh token.

func (*Storage) GetAccessTokenSession

func (s *Storage) GetAccessTokenSession(ctx context.Context, signature string, session fosite.Session) (fosite.Requester, error)

GetAccessTokenSession restores the request an access token was issued for.

func (*Storage) GetAuthorizeCodeSession

func (s *Storage) GetAuthorizeCodeSession(ctx context.Context, code string, session fosite.Session) (fosite.Requester, error)

GetAuthorizeCodeSession restores the request an authorization code was issued for. A code already exchanged returns the request with fosite.ErrInvalidatedAuthorizeCode, so Fosite revokes its tokens.

func (*Storage) GetClient

func (s *Storage) GetClient(ctx context.Context, clientID string) (fosite.Client, error)

GetClient loads an active OAuth client by its client_id.

func (*Storage) GetPKCERequestSession

func (s *Storage) GetPKCERequestSession(ctx context.Context, signature string, session fosite.Session) (fosite.Requester, error)

GetPKCERequestSession restores a code's request with its PKCE challenge.

func (*Storage) GetRefreshTokenSession

func (s *Storage) GetRefreshTokenSession(ctx context.Context, signature string, session fosite.Session) (fosite.Requester, error)

GetRefreshTokenSession restores the request a refresh token was issued for. A rotated refresh token returns the request with fosite.ErrInactiveToken, so Fosite revokes the whole token family.

func (*Storage) InvalidateAuthorizeCodeSession

func (s *Storage) InvalidateAuthorizeCodeSession(ctx context.Context, code string) error

InvalidateAuthorizeCodeSession marks an authorization code as used.

func (*Storage) RevokeAccessToken

func (s *Storage) RevokeAccessToken(ctx context.Context, requestID string) error

RevokeAccessToken revokes every token of the family identified by the Fosite request ID.

func (*Storage) RevokeRefreshToken

func (s *Storage) RevokeRefreshToken(ctx context.Context, requestID string) error

RevokeRefreshToken revokes every token of the family identified by the Fosite request ID.

func (*Storage) RotateRefreshToken added in v0.14.0

func (s *Storage) RotateRefreshToken(ctx context.Context, requestID string, refreshTokenSignature string) error

RotateRefreshToken retires the current tokens of a family before Fosite stores their replacements.

func (*Storage) SetClientAssertionJWT added in v0.14.0

func (s *Storage) SetClientAssertionJWT(ctx context.Context, jti string, exp time.Time) error

SetClientAssertionJWT records a client-assertion JWT ID as used until exp.

type TokenInput

type TokenInput struct {
	GrantType    string `form:"grant_type" required:"true" enum:"authorization_code,refresh_token,client_credentials" doc:"OAuth 2.0 grant type"`
	Code         string `form:"code" doc:"Authorization code (for authorization_code grant)"`
	RedirectURI  string `form:"redirect_uri" doc:"Redirect URI (must match authorization request)"`
	ClientID     string `form:"client_id" doc:"Client identifier (if not using Basic auth)"`
	ClientSecret string `form:"client_secret" doc:"Client secret (if not using Basic auth)"`
	RefreshToken string `form:"refresh_token" doc:"Refresh token (for refresh_token grant)"`
	Scope        string `form:"scope" doc:"Requested scopes (for refresh_token or client_credentials)"`
	CodeVerifier string `form:"code_verifier" doc:"PKCE code verifier"`

	// Basic auth credentials (alternative to form-based client auth)
	Authorization string `header:"Authorization" doc:"Basic authentication header (client_id:client_secret)"`
}

TokenInput represents the OAuth 2.0 token request parameters. Field names follow OAuth 2.0 specification (RFC 6749).

type TokenOutput

type TokenOutput struct {
	Body TokenResponse
}

TokenOutput wraps the token response.

type TokenResponse

type TokenResponse struct {
	AccessToken  string `json:"access_token" doc:"The access token"`
	TokenType    string `json:"token_type" doc:"Token type (typically 'Bearer')"`
	ExpiresIn    int    `json:"expires_in,omitempty" doc:"Token lifetime in seconds"`
	RefreshToken string `json:"refresh_token,omitempty" doc:"Refresh token for obtaining new access tokens"`
	Scope        string `json:"scope,omitempty" doc:"Granted scopes (may differ from requested)"`
	IDToken      string `json:"id_token,omitempty" doc:"OpenID Connect ID token"`
}

TokenResponse represents the OAuth 2.0 token response. Field names follow OAuth 2.0 specification (RFC 6749).

Jump to

Keyboard shortcuts

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