golazy.dev – golazy.dev / lazyoauth Index | Files

package lazyoauth

import "golazy.dev/lazyoauth"

Package lazyoauth provides OAuth server and resource-server primitives.

It is intentionally independent from specific account databases and from MCP. Applications provide lazyauth authenticators, token stores, and claim mapping policy. Signed refresh tokens carry their grant across server restarts while Config.RefreshTokenStates accepts a focused durable RefreshTokenStateStore for rotation, replay detection, and family revocation. lazyapp can then use the same OAuth server for MCP clients such as Codex or Claude, browser-integrated companion applications, or other dependent clients.

Variables

var ErrInvalidClient, ErrInvalidRequest, ErrInvalidGrant, ErrRefreshTokenReplay, ErrUnauthorized, ErrUnsupportedFlow

var (
	ErrInvalidClient	= errors.New("lazyoauth: invalid client")
	ErrInvalidRequest	= errors.New("lazyoauth: invalid request")
	ErrInvalidGrant		= errors.New("lazyoauth: invalid grant")
	ErrRefreshTokenReplay	= errors.New("lazyoauth: refresh token replay detected")
	ErrUnauthorized		= errors.New("lazyoauth: unauthorized")
	ErrUnsupportedFlow	= errors.New("lazyoauth: unsupported flow")
)

Types

type AuthCode

AuthCode is an authorization code record.

type AuthCode struct {
	Code			string		`json:"code"`
	ClientID		string		`json:"client_id"`
	RedirectURI		string		`json:"redirect_uri"`
	CodeChallenge		string		`json:"code_challenge,omitempty"`
	CodeChallengeMethod	string		`json:"code_challenge_method,omitempty"`
	User			lazyauth.User	`json:"user"`
	Scope			[]string	`json:"scope,omitempty"`
	ExpiresAt		time.Time	`json:"expires_at"`
}

type Client

Client is an OAuth client.

type Client struct {
	ID		string		`json:"id"`
	Name		string		`json:"name,omitempty"`
	RedirectURIs	[]string	`json:"redirect_uris"`
	Domain		string		`json:"domain,omitempty"`
}

type Config

Config configures an OAuth authorization server and resource server.

type Config struct {
	Issuer		string
	Resource	string
	Auth		lazyauth.Config
	Store		Store
	// RefreshTokenStates persists the minimal rotation and replay state for
	// signed, self-contained refresh tokens. When nil, Store is used if it
	// implements RefreshTokenStateStore; otherwise an in-memory store is used.
	RefreshTokenStates	RefreshTokenStateStore
	Signer			lazyjwt.Signer
	// Validator overrides the resource-server JWT validator. When empty, a
	// validator is derived from Signer, Issuer, and Resource. The access-token
	// typ requirement remains framework-owned and cannot be overridden.
	Validator	lazyjwt.ValidatorConfig

	ClaimsMapper	ClaimsMapper

	AuthorizePath	string
	TokenPath	string
	RegisterPath	string
	JWKSPath	string

	AccessTokenTTL	time.Duration
	RefreshTokenTTL	time.Duration

	AllowDynamicClients	bool
	// AllowClientIDMetadataDocuments advertises and accepts HTTPS URLs as
	// client IDs. ClientIDMetadataDocumentHosts must contain the exact trusted
	// authorities (host or host:port) from which metadata may be fetched.
	AllowClientIDMetadataDocuments	bool
	ClientIDMetadataDocumentHosts	[]string
	// ClientIDMetadataDocumentHTTPClient overrides the bounded default client,
	// primarily for custom transports and tests. Redirects remain constrained
	// to ClientIDMetadataDocumentHosts.
	ClientIDMetadataDocumentHTTPClient	*http.Client

	// DisableAuthorizationResponseIssuerMetadata omits the RFC 9207 metadata
	// claim that clients must require an iss parameter in authorization
	// responses. The server still emits iss. Use this only as a temporary
	// compatibility workaround for clients that discard iss before validation.
	DisableAuthorizationResponseIssuerMetadata	bool

	// LoginTitle and LoginDescription brand the built-in authorization login
	// page. They are rendered as escaped text and may be left empty for the
	// framework defaults.
	LoginTitle		string
	LoginDescription	string
}

type MemoryStore

MemoryStore is an in-memory OAuth store.

type MemoryStore struct {
	Clients		map[string]Client		`json:"clients"`
	Codes		map[string]AuthCode		`json:"codes"`
	Refresh		map[string]RefreshToken		`json:"refresh"`
	Families	map[string]RefreshTokenFamily	`json:"refresh_token_families"`
	// contains filtered or unexported fields
}
func NewDiskStore

NewDiskStore loads or creates a JSON OAuth store at path.

func NewDiskStore(path string) (*MemoryStore, error)
func NewMemoryStore

NewMemoryStore creates an empty in-memory store.

func NewMemoryStore() *MemoryStore
func (store *MemoryStore) CreateFamily

CreateFamily starts refresh-token rotation state for a newly issued grant.

func (store *MemoryStore) CreateFamily(_ context.Context, family RefreshTokenFamily) error
func (store *MemoryStore) GetClient
func (store *MemoryStore) GetClient(_ context.Context, id string) (Client, error)
func (store *MemoryStore) GetRefreshToken
func (store *MemoryStore) GetRefreshToken(_ context.Context, token string) (RefreshToken, error)
func (store *MemoryStore) RevokeFamily

RevokeFamily invalidates a refresh-token family. It is idempotent.

func (store *MemoryStore) RevokeFamily(_ context.Context, familyID string) error
func (store *MemoryStore) Rotate

Rotate atomically advances a refresh-token family or revokes it on replay.

func (store *MemoryStore) Rotate(_ context.Context, rotation RefreshTokenRotation) error
func (store *MemoryStore) SaveAuthCode
func (store *MemoryStore) SaveAuthCode(_ context.Context, code AuthCode) error
func (store *MemoryStore) SaveClient
func (store *MemoryStore) SaveClient(_ context.Context, client Client) error
func (store *MemoryStore) SaveRefreshToken
func (store *MemoryStore) SaveRefreshToken(_ context.Context, token RefreshToken) error
func (store *MemoryStore) TakeAuthCode
func (store *MemoryStore) TakeAuthCode(_ context.Context, code string) (AuthCode, error)

type RefreshToken

RefreshToken is a legacy opaque refresh token record.

Deprecated: new refresh tokens are signed, self-contained grants whose replay state is persisted through RefreshTokenStateStore. Store retains these methods so existing implementations and previously issued opaque tokens remain compatible during migration.

type RefreshToken struct {
	Token		string		`json:"token"`
	ClientID	string		`json:"client_id"`
	User		lazyauth.User	`json:"user"`
	Scope		[]string	`json:"scope,omitempty"`
	ExpiresAt	time.Time	`json:"expires_at"`
}

type RefreshTokenFamily

RefreshTokenFamily is the minimal server-side state for one rotating refresh token family. The signed token carries the grant; the store tracks only the current token ID and whether the family has been revoked.

type RefreshTokenFamily struct {
	ID		string		`json:"id"`
	CurrentTokenID	string		`json:"current_token_id"`
	ExpiresAt	time.Time	`json:"expires_at"`
	Revoked		bool		`json:"revoked"`
}

type RefreshTokenStateStore

RefreshTokenStateStore tracks refresh-token rotation and family revocation.

Rotate must atomically compare PresentedTokenID with the family's current token ID. A mismatch means replay: the implementation must revoke the family and return ErrRefreshTokenReplay. Missing, expired, or already-revoked families return ErrInvalidGrant. The signed refresh token carries user, client, scope, resource, and expiry data; implementations must not store the token itself. Implementations may opportunistically delete expired or revoked families; a missing family must continue to return ErrInvalidGrant.

type RefreshTokenStateStore interface {
	CreateFamily(context.Context, RefreshTokenFamily) error
	Rotate(context.Context, RefreshTokenRotation) error
	RevokeFamily(context.Context, string) error
}

type Server

Server serves OAuth endpoints and validates bearer tokens.

type Server struct {
	// contains filtered or unexported fields
}
func New

New creates an OAuth server.

func New(config Config) (*Server, error)
func (server *Server) Handler

Handler serves OAuth endpoints and protects non-OAuth requests with bearer token validation.

func (server *Server) Handler(next http.Handler) http.Handler
func (server *Server) HandlesPath

HandlesPath reports whether path belongs to this OAuth server.

func (server *Server) HandlesPath(path string) bool
func (server *Server) Protect

Protect validates bearer tokens before calling next.

func (server *Server) Protect(next http.Handler) http.Handler
func (server *Server) ServeHTTP

ServeHTTP serves OAuth metadata and endpoint requests.

func (server *Server) ServeHTTP(w http.ResponseWriter, r *http.Request)

type Store

Store persists OAuth clients, authorization codes, and refresh tokens.

type Store interface {
	SaveClient(context.Context, Client) error
	GetClient(context.Context, string) (Client, error)
	SaveAuthCode(context.Context, AuthCode) error
	TakeAuthCode(context.Context, string) (AuthCode, error)
	SaveRefreshToken(context.Context, RefreshToken) error
	GetRefreshToken(context.Context, string) (RefreshToken, error)
}