Help us shape the future of Go! Take the 2026 Go Developer Survey

auth

package
v0.5.3 Latest Latest
Warning

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

Go to latest
Published: Nov 3, 2026 License: MIT Imports: 30 Imported by: 0

Documentation

Overview

Package auth provides model-first authentication and typed authorization. Credential strategies verify identity; providers load current models. Neither serialized attribution nor a model reference is evidence of authentication.

Index

Constants

View Source
const MaxAccessScopes = 128

MaxAccessScopes bounds both declarations and restored credential grants.

View Source
const MaxCredentialBytes = 16 << 10
View Source
const MaxCredentials = 32
View Source
const MaxCredentialsBytes = 64 << 10
View Source
const MaxDeviceUserAgentBytes = 512

MaxDeviceUserAgentBytes bounds the user agent stored with a credential.

View Source
const MaxRegistrations = 256
View Source
const MaxRevocationTargets = 32

Variables

This section is empty.

Functions

func BindStrategy

func BindStrategy[M, K, B any](strategy Strategy[M, K], verify func(context.Context, B) (value.Optional[Proof[M, K]], error)) (Strategy[M, K], Binder[B])

BindStrategy extends a strategy to verify the bound credentials its returned Binder creates. Request secrets are verified exactly as before. A bound credential from any other binder is unauthenticated.

func ConfirmationKeys

func ConfirmationKeys() keyspace.Codec[ConfirmationKey]

ConfirmationKeys is the key codec for confirmation lockout declarations, for example lockout.Define("accounts.confirm", auth.ConfirmationKeys(), lockout.DefaultPolicy()).

func CurrentCredential

func CurrentCredential[M, C any](ctx context.Context, guard Guard[M], slot CredentialSlot[C]) (C, error)

CurrentCredential returns the metadata the guard's strategy attached for the credential that authenticated this scope. It reuses the scope's cached guard result: no second verification or lookup runs. An anonymous or pending scope fails like Require; a guard whose strategy uses another slot returns Missing.

func NewDenial

func NewDenial(code DenialCode, message string) error

NewDenial returns a typed denial. The message must be safe for the caller to see.

func Notify

func Notify(ctx context.Context, observer Observer, event Event)

Notify invokes observer, when present, with the request metadata from ctx. Panics and Goexit are contained; the observed operation's result is final.

func RegisterAuthorization

func RegisterAuthorization[D authorizationDeclaration](r *foundation.Registrar, key foundation.Key[*Registry], declaration D) error

RegisterAuthorization adds the existing typed guard, policy, permission or Before/After hook declaration to an application registry. Its subject/resource types remain part of override validation, and its exact declaration identity is retained for auth checks.

func RegisterRegistry

func RegisterRegistry(r *foundation.Registrar, key foundation.Key[*Registry], config Config) error

RegisterRegistry assembles contributed guards and policies through the same bounded immutable registry used by direct application construction.

Types

type AccessScope

type AccessScope[M any] struct {
	// contains filtered or unexported fields
}

AccessScope declares a credential capability owned by one subject model. Scope checks restrict credentials; policies still authorize current resources.

func DefineAccessScope

func DefineAccessScope[M any](name AccessScopeName) AccessScope[M]

DefineAccessScope declares a credential capability for model M; Validate checks its name.

func (AccessScope[M]) Name

func (s AccessScope[M]) Name() AccessScopeName

Name returns the declared capability name.

func (AccessScope[M]) Validate

func (s AccessScope[M]) Validate() error

Validate requires a semantic capability name without wildcards.

type AccessScopeName

type AccessScopeName string

AccessScopeName is a persisted credential capability, not a model permission.

type AccessScopes

type AccessScopes[M any] struct {
	// contains filtered or unexported fields
}

AccessScopes is an immutable set owned by one subject model. Zero grants nothing. Names returns a copy; caller mutations cannot change a verified proof.

func NewAccessScopes

func NewAccessScopes[M any](scopes ...AccessScope[M]) (AccessScopes[M], error)

NewAccessScopes builds an immutable sorted set, rejecting invalid names, duplicates and more than MaxAccessScopes entries.

func (AccessScopes[M]) Contains

func (s AccessScopes[M]) Contains(scope AccessScope[M]) bool

Contains reports whether the set grants scope; invalid scopes never match.

func (AccessScopes[M]) ContainsAll

func (s AccessScopes[M]) ContainsAll(required AccessScopes[M]) bool

ContainsAll reports set inclusion; every set includes the empty set. A guard requirement separately rejects an empty set to prevent an accidental no-op.

func (AccessScopes[M]) Intersect

func (s AccessScopes[M]) Intersect(other AccessScopes[M]) AccessScopes[M]

Intersect returns the scopes present in both sets. Credential adapters use it to apply a binding's current ceiling to stored grants: removing a scope from the ceiling withdraws it from existing credentials without making them unreadable. The result is never larger than either input.

func (AccessScopes[M]) Len

func (s AccessScopes[M]) Len() int

Len returns the number of granted capabilities.

func (AccessScopes[M]) Names

func (s AccessScopes[M]) Names() []AccessScopeName

Names returns a copy of the sorted capability names.

type After

type After[M any] struct {
	// contains filtered or unexported fields
}

After runs once a policy or permission for model M allowed a request. It may veto with Deny (for example a global read-only mode) but can never turn a denial into an allow. Allow and Abstain keep the policy's decision.

func DefineAfter

func DefineAfter[M any](name PolicyName, veto func(context.Context, M, PolicyName) (Verdict, error)) After[M]

DefineAfter declares a veto-only hook. See After for its restricted contract.

func (After[M]) Name

func (a After[M]) Name() PolicyName

Name returns the hook name, or an empty name for an undefined hook.

func (After[M]) Registration

func (a After[M]) Registration() Registration

Registration returns the veto hook's declaration for a registry.

func (After[M]) Validate

func (a After[M]) Validate() error

Validate requires a declared hook with a semantic name and callback.

type Assurance

type Assurance uint8

Assurance is set by a trusted strategy after credential verification. PendingMFA can never enter an ordinary authenticated handler or policy.

const (
	PendingMFA Assurance = iota + 1
	Authenticated
)

func (Assurance) Validate

func (a Assurance) Validate() error

Validate checks a restored credential's assurance before it can be used.

type Before

type Before[M any] struct {
	// contains filtered or unexported fields
}

Before runs ahead of every policy and permission evaluated for model M in a registry that contains it, for example to let a verified super-administrator pass checks or to deny a suspended tenant everywhere. Hooks run in registration order and the first Allow or Deny decides; the policy callback then does not run. A hook receives the current request's model and the policy name, never the resource. Errors deny; they never grant.

func DefineBefore

func DefineBefore[M any](name PolicyName, decide func(context.Context, M, PolicyName) (Verdict, error)) Before[M]

DefineBefore declares a model hook that may allow, deny or defer before policy evaluation.

func (Before[M]) Name

func (b Before[M]) Name() PolicyName

Name returns the hook name, or an empty name for an undefined hook.

func (Before[M]) Registration

func (b Before[M]) Registration() Registration

Registration returns the before hook's declaration for a registry.

func (Before[M]) Validate

func (b Before[M]) Validate() error

Validate requires a declared hook with a semantic name and callback.

type Binder

type Binder[B any] struct {
	// contains filtered or unexported fields
}

Binder creates bound credentials that only its own strategy verifies.

func (Binder[B]) Bind

func (b Binder[B]) Bind(bound B) (BoundCredential, error)

Bind wraps bound with this binder's identity. It does not verify the credential or clone bound.

type BoundCredential

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

BoundCredential stands in for a credential that a trusted boundary has already exchanged, such as a redeemed single-use handshake ticket. Transport capture never creates one: only the Binder returned with a strategy can, and only that strategy verifies it, so request input can never present one. Every new scope re-verifies it, observing revocation and current eligibility like any other credential. Formatting never reveals its contents.

func (BoundCredential) Format

func (BoundCredential) Format(s fmt.State, _ rune)

Format writes a credential label without exposing its bound value.

func (BoundCredential) IsZero

func (b BoundCredential) IsZero() bool

IsZero reports an absent bound credential.

type Code

type Code string

Code is a transport-independent, stable authentication failure.

const (
	Unauthenticated Code = "unauthenticated"
	Forbidden       Code = "forbidden"
	MFARequired     Code = "mfa_required"
	// CredentialLimit rejects issuing another session/token when the subject's
	// active-credential cap is reached under a reject-new policy. It is a client
	// conflict (revoke an existing credential), not a server failure.
	CredentialLimit Code = "credential_limit"
	// ConfirmationRequired rejects a sensitive operation until the current
	// session recently re-entered its password.
	ConfirmationRequired Code = "password_confirmation_required"
	// ImpersonationForbidden rejects an operation that an impersonated session
	// must not perform, such as changing credentials or starting another
	// impersonation. It is a Forbidden-class refusal.
	ImpersonationForbidden Code = "impersonation_forbidden"
)

func (Code) Error

func (c Code) Error() string

Error returns the authentication error code text.

func (Code) WithCause

func (c Code) WithCause(cause error) error

WithCause retains diagnostic identity without formatting credential details.

type Config

type Config struct {
	MaxConcurrent int
	Timeout       time.Duration
}

Config bounds concurrent callbacks across all scopes owned by this registry. Timeout covers each verification/provider resolution or policy evaluation. A burst queues for at most min(Timeout, 5s) before the budget starts; an unsatisfied wait reports fault.Overloaded. A callback that ignores cancellation still owns its slot until actual exit.

func DefaultConfig

func DefaultConfig() Config

DefaultConfig returns default authentication callback concurrency and timeout bounds.

func (Config) Validate

func (c Config) Validate() error

Validate requires bounded positive concurrency and a positive timeout.

type ConfirmationKey

type ConfirmationKey string

ConfirmationKey is the lockout key of one subject's password confirmations: a fixed-size digest of the provider and stored identity, never the identity.

type Credential

type Credential struct {
	Name   CredentialName
	Secret secret.String
}

Credential is a transport adapter's input. Omit missing sources entirely; a present empty secret is invalid and must not become anonymous access.

type CredentialName

type CredentialName string

CredentialName identifies a declared input source, such as api.bearer. It is not a guard name, permission, cookie name or credential value.

type CredentialSlot

type CredentialSlot[C any] struct {
	// contains filtered or unexported fields
}

CredentialSlot is a trusted credential adapter's typed channel from the proof it verified to code running in the same authentication scope, such as the session or token metadata behind the current request. Only holders of the slot value can attach or read it; attached metadata never becomes a claim, grant or authority, and a new scope verifies the credential again.

func NewCredentialSlot

func NewCredentialSlot[C any]() CredentialSlot[C]

NewCredentialSlot creates a unique typed credential-metadata slot.

func (CredentialSlot[C]) Validate

func (s CredentialSlot[C]) Validate() error

Validate checks that the slot was declared. The zero slot is invalid.

type Credentials

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

Credentials is an immutable bounded input snapshot for one authorization scope. Routine formatting and JSON never expose its contents.

func NewCredentials

func NewCredentials(inputs ...Credential) (Credentials, error)

NewCredentials copies bounded credential secrets into a set, rejecting invalid or duplicate sources and empty or oversized secrets.

func (Credentials) Format

func (Credentials) Format(s fmt.State, _ rune)

Format writes a credentials label without exposing secrets.

func (Credentials) Get

Get returns an immutable secret for a declared source. Zero means absent; transport adapters cannot construct a present empty credential.

func (Credentials) WithBound

func (c Credentials) WithBound(name CredentialName, bound BoundCredential) (Credentials, error)

WithBound returns a copy that also carries a bound credential for one declared source. A source carries either a transport secret or a bound credential, never both, so an ambiguous combination fails instead.

type Decision

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

Decision is an inspected authorization outcome. A denied decision may carry the typed Denial returned by a policy or hook; Allowed never carries one.

func (Decision) Allowed

func (d Decision) Allowed() bool

Allowed reports whether the authorization decision grants access. The zero decision denies.

func (Decision) Denial

func (d Decision) Denial() (*Denial, bool)

Denial returns the typed reason when the policy supplied one.

func (Decision) Err

func (d Decision) Err() error

Err returns nil when allowed, the typed denial when present, or Forbidden.

type Denial

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

Denial is a typed Forbidden decision carrying a stable code and a safe public message. Return it from a policy callback (false, auth.NewDenial(...)) or a hook error to explain a denial; errors.Is(err, auth.Forbidden) remains true. To publish the code over HTTP, wrap it in a declared endpoint error.

func (*Denial) Code

func (d *Denial) Code() DenialCode

Code returns the application denial code, or an empty code for a nil denial.

func (*Denial) Error

func (d *Denial) Error() string

Error returns the Forbidden code without exposing the public message.

func (*Denial) Is

func (d *Denial) Is(target error) bool

Is reports whether target is Forbidden.

func (*Denial) Message

func (d *Denial) Message() string

Message returns the safe public denial message, or an empty string for a nil denial.

type DenialCode

type DenialCode string

DenialCode is an application-owned reason for a denied authorization. It is a stable semantic identifier such as orders.closed, not a translated message.

type Device

type Device struct {
	ClientIP  netip.Addr
	UserAgent string
}

Device is display metadata about the client that obtained a session or token, for "your devices" listings. It is captured from the trusted request attribution at issuance and is never used to authenticate or authorize.

func DeviceFrom

func DeviceFrom(ctx context.Context) Device

DeviceFrom captures the current request's trusted client IP and user agent. The user agent is truncated on a rune boundary to MaxDeviceUserAgentBytes. Contexts without request attribution return a zero Device.

func (Device) Validate

func (d Device) Validate() error

Validate checks the IP zone and bounded, control-free UTF-8 user agent.

type EnrolledFactors

type EnrolledFactors[M any] interface {
	// HasEnrolledFactor reports whether the current model has an enrolled second factor.
	HasEnrolledFactor(context.Context, M) (bool, error)
}

EnrolledFactors reports whether a model currently has a confirmed second factor. mfa.Factors implements it from the model's stored enabled state.

type Event

type Event struct {
	Kind         EventKind
	Guard        GuardName
	Provider     ProviderName
	Subject      value.Optional[model.Identity]
	Impersonator value.Optional[model.Identity]
	Request      attribution.Request
	Count        uint64
}

Event is safe lifecycle metadata. It never contains a password, secret, hash, submitted login key or model snapshot. Subject is the affected stored identity when known; Impersonator is the original actor for impersonation events and for events in an impersonated session; Request is the initiating request's trusted metadata.

func (Event) Format

func (Event) Format(s fmt.State, _ rune)

Format writes an event label without exposing event data.

type EventKind

type EventKind string

EventKind identifies an authentication lifecycle transition.

const (
	// EventLogin: a full (not pending-MFA) session or token was issued.
	EventLogin EventKind = "login"
	// EventLogout: the current credential was revoked by its holder.
	EventLogout EventKind = "logout"
	// EventFailed: a password attempt was rejected. Subject is omitted when no
	// account matched, so the event never confirms submitted identifiers.
	EventFailed EventKind = "failed"
	// EventLockout: failed attempts started a temporary lockout.
	EventLockout EventKind = "lockout"
	// EventPasswordReset: a recovery link replaced the password.
	EventPasswordReset EventKind = "password_reset"
	// EventVerified: an email verification link was consumed.
	EventVerified EventKind = "verified"
	// EventOtherDevicesLoggedOut: every other credential was revoked while the
	// current one was kept. Count reports the provisional revoked total.
	EventOtherDevicesLoggedOut EventKind = "other_devices_logged_out"
	// EventImpersonationStarted: Impersonator began acting as Subject.
	EventImpersonationStarted EventKind = "impersonation_started"
	// EventImpersonationStopped: the impersonation session of Subject ended
	// and Impersonator returned to its own identity.
	EventImpersonationStopped EventKind = "impersonation_stopped"
)

type Guard

type Guard[M any] struct {
	// contains filtered or unexported fields
}

Guard retains the concrete authenticated model while its strategy/provider preserve the key type at construction. A model may have multiple guards.

func DefineGuard

func DefineGuard[M model.Identifiable, K any](name GuardName, provider Provider[M, K], strategy Strategy[M, K]) Guard[M]

DefineGuard binds a named guard to the exact provider and credential strategy declarations. Resolution verifies supplied credentials before loading the current eligible model.

func (Guard[M]) Name

func (g Guard[M]) Name() GuardName

Name returns the guard name, or an empty name for an undefined guard.

func (Guard[M]) Optional

func (g Guard[M]) Optional(ctx context.Context) (value.Optional[M], error)

Optional returns an omitted model only when this guard's credential is absent. Invalid, revoked, missing-model and disabled-account credentials remain errors. Verification and model lookup coalesce once per guard declaration per scope; failures are cached too. A canceled initiating call cannot cause an implicit retry. Other waiters may cancel without canceling the initiating operation.

func (Guard[M]) Origin

func (g Guard[M]) Origin(ctx context.Context) (attribution.Origin, error)

Origin captures provenance from this guard's verified identity and the current request metadata. It reuses the scope's existing resolution, without another provider lookup or model getter. Pending/absent/invalid credentials fail; an inherited model/system origin never substitutes for this guard's verification. The result is serializable metadata, not authority for a later job or message.

func (Guard[M]) ProviderName

func (g Guard[M]) ProviderName() ProviderName

ProviderName returns the bound provider name, or an empty name for an undefined guard.

func (Guard[M]) Registration

func (g Guard[M]) Registration() Registration

Registration returns the guard's identity and validation contract for a registry.

func (Guard[M]) Require

func (g Guard[M]) Require(ctx context.Context) (M, error)

Require returns the concrete model after current credential and provider checks. It never returns a partial model on error and never accepts MFA-pending credentials. Reference-valued model fields remain read-only shared scope data.

func (Guard[M]) RequireScopes

func (g Guard[M]) RequireScopes(ctx context.Context, required AccessScopes[M]) (M, error)

RequireScopes returns the concrete model only when the credential explicitly grants every required scope. It rejects empty requirements, missing grants and pending MFA. Resolution shares Require/Optional's once-per-request model lookup. This does not replace a current model/resource policy decision.

func (Guard[M]) Source

func (g Guard[M]) Source() CredentialName

Source is the named credential input verified by this guard's strategy.

func (Guard[M]) Validate

func (g Guard[M]) Validate() error

Validate checks the guard name and its provider and strategy declarations.

func (Guard[M]) ValidateIn

func (g Guard[M]) ValidateIn(registry *Registry) error

ValidateIn checks assembly registration without verifying credentials or loading a model. Matching names alone never substitute for the registered declaration.

func (Guard[M]) WithAttribution

func (g Guard[M]) WithAttribution(ctx context.Context) (context.Context, error)

WithAttribution derives a context for audit/event work inside the current authorization scope. Cancellation and existing context values are preserved. HTTP typed authentication adapters do this automatically before input decoding. For deferred work capture Origin only, then create a fresh execution context and independently select/verify its authority. Never retain the authentication scope.

type GuardName

type GuardName string

GuardName identifies an authentication guard declaration.

type GuestPolicy

type GuestPolicy[M, R any] struct {
	// contains filtered or unexported fields
}

GuestPolicy evaluates a resource for an optional model: anonymous requests receive an omitted value instead of an Unauthenticated error. Invalid, revoked or pending credentials still fail. Before/After hooks apply only when a model is present. It shares the policy registry namespace.

func DefineGuestPolicy

func DefineGuestPolicy[M, R any](name PolicyName, evaluate func(context.Context, value.Optional[M], R) (bool, error)) GuestPolicy[M, R]

DefineGuestPolicy declares a resource policy that receives an omitted subject for anonymous requests.

func (GuestPolicy[M, R]) Allows

func (p GuestPolicy[M, R]) Allows(ctx context.Context, guard Guard[M], resource R) (bool, error)

Allows evaluates the guest policy and returns whether the decision allows access.

func (GuestPolicy[M, R]) Authorize

func (p GuestPolicy[M, R]) Authorize(ctx context.Context, guard Guard[M], resource R) error

Authorize evaluates the guest policy and returns its denial error when access is refused.

func (GuestPolicy[M, R]) Inspect

func (p GuestPolicy[M, R]) Inspect(ctx context.Context, guard Guard[M], resource R) (Decision, error)

Inspect evaluates the registered policy for the optional current subject, preserving typed denial reasons. Invalid credentials still fail.

func (GuestPolicy[M, R]) Name

func (p GuestPolicy[M, R]) Name() PolicyName

Name returns the underlying policy name.

func (GuestPolicy[M, R]) Registration

func (p GuestPolicy[M, R]) Registration() Registration

Registration returns the guest policy's declaration for a registry.

func (GuestPolicy[M, R]) Validate

func (p GuestPolicy[M, R]) Validate() error

Validate checks the underlying policy declaration.

func (GuestPolicy[M, R]) ValidateIn

func (p GuestPolicy[M, R]) ValidateIn(registry *Registry) error

ValidateIn checks that this exact guest policy declaration belongs to registry.

type LimitPolicy

type LimitPolicy string

LimitPolicy selects what a credential store does when issuing would exceed a subject's active-credential cap. Pending-MFA credentials use their own small cap and always replace the oldest pending credential.

const (
	// RejectNew keeps existing credentials and fails issuance with CredentialLimit.
	RejectNew LimitPolicy = "reject_new"
	// EvictOldest revokes the subject's oldest active credentials of the same
	// kind so the new one fits. It never revokes pending-MFA credentials.
	EvictOldest LimitPolicy = "evict_oldest"
)

func (LimitPolicy) Validate

func (p LimitPolicy) Validate() error

Validate accepts only RejectNew and EvictOldest.

type Observer

type Observer func(context.Context, Event)

Observer receives an in-process notification after the transition finished (after commit for persisted changes). It cannot veto or undo the change and is not durable delivery: for durable processing, publish an application event through the transactional outbox from the owning domain transaction instead. Observers must be fast, concurrency-safe and honor ctx.

type PasswordLogin

type PasswordLogin[M model.Identifiable, K, I any] struct {
	// contains filtered or unexported fields
}

PasswordLogin verifies one typed login key using a shared model provider and hasher. Construction performs no I/O. Share it across requests. Config bounds its callbacks; the hasher independently bounds expensive Argon2 operations. WithLockout adds shared failed-attempt protection; request-rate limiting runs before expensive verification. Credential issuance is a subsequent operation. Its proof carries a transaction check that locks and revalidates the current hash, eligibility and MFA policy before credential insertion. Guards recheck models at use time.

func NewPasswordLogin

func NewPasswordLogin[M model.Identifiable, K, I any](provider Provider[M, K], hasher *password.Hasher, binding PasswordModel[M, I], config Config) (*PasswordLogin[M, K, I], error)

NewPasswordLogin validates and binds the provider, hasher and password model with bounded verification admission.

func (*PasswordLogin[M, K, I]) Authenticate

func (l *PasswordLogin[M, K, I]) Authenticate(ctx context.Context, key I, plain password.Plaintext) (PasswordResult[M, K], error)

Authenticate returns one concrete model and its proof, with no second model lookup. Missing, disabled, unusable-password and wrong-password cases expose Unauthenticated. Operational failures remain errors. Every failure returns a zero result. Rehash uses compare-and-swap. Losing it to a concurrent login's rehash re-verifies the password against the winning hash and continues; if the password itself changed, the attempt fails without counting as a lockout failure and never issues credentials for the replaced password.

func (*PasswordLogin[M, K, I]) Confirm

func (l *PasswordLogin[M, K, I]) Confirm(ctx context.Context, subject M, plain password.Plaintext) error

Confirm re-verifies plain against subject's stored hash for a password confirmation step. Pass the current model from the request's guard. It runs no lookup or lockout (the caller is authenticated; apply request-rate limits) and returns Unauthenticated for a mismatch or unusable hash.

func (*PasswordLogin[M, K, I]) Validate

func (l *PasswordLogin[M, K, I]) Validate() error

Validate checks that password login has been configured.

func (*PasswordLogin[M, K, I]) WithConfirmationLockout

func (l *PasswordLogin[M, K, I]) WithConfirmationLockout(throttle lockout.Throttle[ConfirmationKey]) (*PasswordLogin[M, K, I], error)

WithConfirmationLockout counts failed Confirm attempts per subject, so a stolen session cookie cannot brute-force the password through a confirmation screen. Use a declaration separate from the login throttle. A locked subject fails Confirm with lockout.Locked (HTTP 429) before hashing.

func (*PasswordLogin[M, K, I]) WithLockout

func (l *PasswordLogin[M, K, I]) WithLockout(throttle lockout.Throttle[I]) (*PasswordLogin[M, K, I], error)

WithLockout returns a login view using the same typed login key for lookup and failed-attempt protection. It preserves the original callback capacity and shared hasher. Use a password-specific lockout.DefineLogin declaration: its client-aware limits stop one source from locking a victim out for everyone. Single-key lockout.Define throttles are rejected here. MFA/recovery use separate policies so successful password verification cannot clear them.

func (*PasswordLogin[M, K, I]) WithObserver

func (l *PasswordLogin[M, K, I]) WithObserver(observer Observer) (*PasswordLogin[M, K, I], error)

WithObserver returns a login view that reports EventFailed (with Subject only when an account matched) and EventLockout (when a failure starts a lock). Successful logins are reported by the session/token store that issues them.

func (*PasswordLogin[M, K, I]) WithSecondFactor

func (l *PasswordLogin[M, K, I]) WithSecondFactor(factors EnrolledFactors[M]) (*PasswordLogin[M, K, I], error)

WithSecondFactor links enrolled factors at construction: login and issuance rechecks then require MFA whenever RequiresMFA or an enrolled factor says so, so a RequiresMFA callback that forgets the factor state cannot bypass MFA.

type PasswordModel

type PasswordModel[M model.Identifiable, I any] struct {
	// Lookup uses the application's normalized login key and tenant scope. Missing
	// models return an omitted Optional. Enforce uniqueness in the database.
	Lookup func(context.Context, I) (value.Optional[M], error)
	// Lock uses the supplied issuance transaction and the prior model's typed
	// primary key to return a current full model with a generated ForUpdate query.
	// It is invoked when a credential is issued, after password verification. This
	// closes the gap where a reset could otherwise precede issuance of an old proof.
	Lock func(context.Context, *database.Tx, M) (value.Optional[M], error)
	// Hash returns the stored value, never a presentation getter's replacement.
	// Zero means an account has no usable password; login rejects it uniformly.
	Hash func(M) password.Hash
	// Rehash conditionally replaces old with next in the authoritative store.
	// Compare old in the same transaction as the write and return its complete
	// resulting model. Omit the result when a concurrent password change wins.
	// Preserve ordinary model lifecycle behavior. Never retry uncertain writes.
	Rehash func(ctx context.Context, subject M, old, next password.Hash) (value.Optional[M], error)
	// RequiresMFA checks current factor policy. It is explicit even when false;
	// a required second factor produces only a PendingMFA proof. Link enrolled
	// factors with PasswordLogin.WithSecondFactor so enrollment always applies.
	RequiresMFA func(context.Context, M) (bool, error)
}

PasswordModel supplies domain behavior for one concrete model and login key. All callbacks are required, concurrency-safe and context-aware. Returned models own their data; treat reference-valued fields as read-only. Foundry handles verification, rehash decisions, eligibility and assurance. No Actor or second provider lookup is involved.

func (PasswordModel[M, I]) Validate

func (m PasswordModel[M, I]) Validate() error

Validate requires lookup, transactional locking, hash access, conditional rehash and MFA-policy callbacks.

type PasswordResult

type PasswordResult[M, K any] struct {
	// contains filtered or unexported fields
}

PasswordResult retains the resolved model and verified proof. It is a trusted server result, not a response DTO. PendingMFA subjects still require their second factor; do not use Subject as an authorization shortcut. Ordinary guards reject that proof. A zero result has no valid proof. Keep this result within its server-side request; it is not a reusable reauthentication ticket.

func (PasswordResult[M, K]) Format

func (PasswordResult[M, K]) Format(s fmt.State, _ rune)

Format writes a result label without exposing the subject or proof.

func (PasswordResult[M, K]) Proof

func (r PasswordResult[M, K]) Proof() Proof[M, K]

Proof returns the verified authentication proof.

func (PasswordResult[M, K]) Subject

func (r PasswordResult[M, K]) Subject() M

Subject returns the resolved model without cloning reference-valued fields.

type Permission

type Permission[M any] struct {
	// contains filtered or unexported fields
}

Permission is a model-owned policy without a resource argument. Its callback decides from the authenticated model and current domain state, not serialized credential claims. It reuses Policy's registration, bounds and failure handling.

func DefinePermission

func DefinePermission[M any](name PermissionName, evaluate func(context.Context, M) (bool, error)) Permission[M]

DefinePermission declares a named model permission evaluated through the policy machinery.

func (Permission[M]) Allows

func (p Permission[M]) Allows(ctx context.Context, guard Guard[M]) (bool, error)

Allows evaluates the registered permission for guard's current subject and returns whether access is allowed.

func (Permission[M]) Authorize

func (p Permission[M]) Authorize(ctx context.Context, guard Guard[M]) error

Authorize evaluates the permission and returns a denial error when access is refused.

func (Permission[M]) Description

func (p Permission[M]) Description() (PermissionDescription, error)

Description validates the permission and returns its name and translation key.

func (Permission[M]) Inspect

func (p Permission[M]) Inspect(ctx context.Context, guard Guard[M]) (Decision, error)

Inspect returns the decision, including a typed Denial when one was given.

func (Permission[M]) LabelKey

func (p Permission[M]) LabelKey() i18n.MessageKey

LabelKey returns the permission's display-label translation key.

func (Permission[M]) Name

func (p Permission[M]) Name() PermissionName

Name returns the declared permission name.

func (Permission[M]) Registration

func (p Permission[M]) Registration() Registration

Registration returns the underlying policy registration with permission validation.

func (Permission[M]) Validate

func (p Permission[M]) Validate() error

Validate checks retained declaration errors and the underlying policy.

func (Permission[M]) ValidateIn

func (p Permission[M]) ValidateIn(registry *Registry) error

ValidateIn checks that this exact permission declaration belongs to registry.

func (Permission[M]) WithLabelKey

func (p Permission[M]) WithLabelKey(key i18n.MessageKey) Permission[M]

WithLabelKey copies only presentation metadata. The exact registered policy identity, model ownership and fresh authorization evaluator remain unchanged.

type PermissionDescription

type PermissionDescription struct {
	Name     PermissionName  `json:"name"`
	LabelKey i18n.MessageKey `json:"label_key,omitempty"`
}

PermissionDescription carries a permission's stable name and optional display-label translation key.

type PermissionName

type PermissionName string

PermissionName identifies a current model capability, distinct from a token's persisted AccessScopeName. Permissions and resource policies share one registry namespace and execution pipeline; duplicate names cannot replace declarations.

type Policy

type Policy[M, R any] struct {
	// contains filtered or unexported fields
}

Policy retains both subject and resource types. It loads the subject through the supplied matching guard; callers cannot substitute an unauthenticated model. Decisions are evaluated each time, never cached as credential claims. Registered Before/After hooks for the same model run around the callback.

func DefinePolicy

func DefinePolicy[M, R any](name PolicyName, evaluate func(context.Context, M, R) (bool, error)) Policy[M, R]

DefinePolicy declares a named resource evaluator for model M; Validate checks its name and callback.

func (Policy[M, R]) Allows

func (p Policy[M, R]) Allows(ctx context.Context, guard Guard[M], resource R) (bool, error)

Allows evaluates the registered policy and hooks for the current subject and resource and reports whether access is allowed.

func (Policy[M, R]) Authorize

func (p Policy[M, R]) Authorize(ctx context.Context, guard Guard[M], resource R) error

Authorize evaluates the policy and returns its denial error when access is refused.

func (Policy[M, R]) Inspect

func (p Policy[M, R]) Inspect(ctx context.Context, guard Guard[M], resource R) (Decision, error)

Inspect evaluates registered Before hooks, the policy and After vetoes for the current model, returning the decision and any typed Denial instead of only a boolean. Operational failures remain errors and never allow.

func (Policy[M, R]) Name

func (p Policy[M, R]) Name() PolicyName

Name returns the policy name, or an empty name for an undefined policy.

func (Policy[M, R]) Registration

func (p Policy[M, R]) Registration() Registration

Registration returns the policy's identity and validation contract for a registry.

func (Policy[M, R]) Validate

func (p Policy[M, R]) Validate() error

Validate requires a semantic name and evaluator. The zero policy is invalid.

func (Policy[M, R]) ValidateIn

func (p Policy[M, R]) ValidateIn(registry *Registry) error

ValidateIn checks exact declaration registration at assembly time without resolving a model or evaluating a decision. Matching names are insufficient.

type PolicyName

type PolicyName string

PolicyName identifies a policy or authorization hook declaration.

type Proof

type Proof[M, K any] struct {
	// contains filtered or unexported fields
}

Proof is a verified strategy result retaining model/key ownership. It freezes stored identity metadata and contains no credential or authoritative roles. Only trusted credential adapters should create proofs; construction itself does not verify a password, signature, expiry, revocation or database record.

func AttachCredential

func AttachCredential[M, K, C any](proof Proof[M, K], slot CredentialSlot[C], metadata C) (Proof[M, K], error)

AttachCredential returns a copy of a verified proof carrying credential metadata for its adapter's slot. It is a trusted adapter boundary: attach only metadata of the credential that was actually verified. A proof carries at most one attachment; grants and issuance checks are preserved.

func AttachImpersonatedCredential

func AttachImpersonatedCredential[M, K, C any](proof Proof[M, K], slot CredentialSlot[C], metadata C) (Proof[M, K], error)

AttachImpersonatedCredential is AttachCredential for a credential issued by impersonation. CurrentProof then refuses the scope with ImpersonationForbidden, so an impersonator can never mint an unmarked token or session for the subject.

func CurrentProof

func CurrentProof[M model.Identifiable, K any](ctx context.Context, provider Provider[M, K], guard Guard[M]) (Proof[M, K], error)

CurrentProof returns a proof for the model that authenticated guard in this scope, retaining the verified credential's access-scope grants. Issuing a new token from it therefore inherits, and can only narrow, the request's grants, instead of minting an unrestricted proof with NewProof. The provider must be the guard's own declaration. The proof carries no issuance check or metadata. A scope authenticated by an impersonation credential is refused with ImpersonationForbidden.

func NewProof

func NewProof[M, K any](reference model.Reference[M, K], assurance Assurance) (Proof[M, K], error)

NewProof validates the reference and assurance and constructs a trusted adapter result. Construction does not verify submitted credentials.

func NewScopedProof

func NewScopedProof[M, K any](reference model.Reference[M, K], assurance Assurance, scopes AccessScopes[M]) (Proof[M, K], error)

NewScopedProof is a trusted strategy boundary after credential verification. The immutable grants came from the authoritative credential store, never from unverified request scope names. Empty grants remain an explicitly scoped proof.

func (Proof[M, K]) AccessScopes

func (p Proof[M, K]) AccessScopes() (AccessScopes[M], bool)

AccessScopes returns verified credential restrictions and whether the proof carries scope grants. Unscoped proofs cannot satisfy RequireScopes.

func (Proof[M, K]) Assurance

func (p Proof[M, K]) Assurance() Assurance

Assurance returns the proof's authentication assurance.

func (Proof[M, K]) CheckIssuance

func (p Proof[M, K]) CheckIssuance(ctx context.Context, tx *database.Tx) error

CheckIssuance is called by a transactional credential backend. The caller owns the transaction, context timeout and operation capacity. Failures preserve error identity while isolating panic/Goexit. A checked proof cannot be persisted by an adapter without the corresponding atomic creation capability.

func (Proof[M, K]) Format

func (Proof[M, K]) Format(s fmt.State, _ rune)

Format writes a proof label without exposing identity or credential data.

func (Proof[M, K]) HasIssuanceCheck

func (p Proof[M, K]) HasIssuanceCheck() bool

HasIssuanceCheck reports whether the proof carries a transactional revalidation callback.

func (Proof[M, K]) Identity

func (p Proof[M, K]) Identity() model.Identity

Identity returns the proof's stored model identity.

func (Proof[M, K]) WithAccessScopes

func (p Proof[M, K]) WithAccessScopes(scopes AccessScopes[M]) (Proof[M, K], error)

WithAccessScopes narrows a verified proof while preserving its issuance check. It cannot expand an existing grant. Use this instead of reconstructing a new proof from its identity, which would discard verification provenance.

func (Proof[M, K]) WithIssuanceCheck

func (p Proof[M, K]) WithIssuanceCheck(check func(context.Context, *database.Tx) error) (Proof[M, K], error)

WithIssuanceCheck binds trusted verification to its later persistence step. The check MUST lock and revalidate current domain state on tx. It runs before credential-store locks in the same transaction as creation, never afterward. A check cannot be replaced. The callback may be invoked by separate Issue calls and must be safe for concurrent use; it never commits or retries. This is a trusted adapter boundary, not a way to verify submitted identities.

type Provider

type Provider[M model.Identifiable, K any] struct {
	// contains filtered or unexported fields
}

Provider preserves the model and its generated stored primary-key type. Reuse the same declaration when session and token guards share a provider.

func DefineProvider

func DefineProvider[M model.Identifiable, K any](name ProviderName, reference model.Reference[M, K], lookup func(context.Context, K) (value.Optional[M], error), eligible func(context.Context, M) (bool, error)) Provider[M, K]

DefineProvider uses generated reference metadata, avoiding repeated table/key codecs. Lookup returns an omitted Optional for missing/deleted models. Eligible checks current account state (for example disabled status); it is mandatory. Callbacks must honor cancellation, be concurrency-safe, and return owned hydrated values. M must be a model struct. Treat reference-valued fields in returned models as read-only for the scope, or clone them before modification.

func (Provider[M, K]) CheckModel

func (p Provider[M, K]) CheckModel(ctx context.Context, subject M) (model.Reference[M, K], error)

CheckModel validates an already loaded model's stored identity and current eligibility, without a second lookup. Transactional framework adapters use it after locking the model. This does NOT verify a credential or grant authority. The caller owns freshness and bounds execution with its operation context.

func (Provider[M, K]) ModelName

func (p Provider[M, K]) ModelName() string

ModelName returns the provider's reference model name, or an empty string for an undefined provider.

func (Provider[M, K]) Name

func (p Provider[M, K]) Name() ProviderName

Name returns the provider name, or an empty name for an undefined provider.

func (Provider[M, K]) Parse

func (p Provider[M, K]) Parse(identity model.Identity) (model.Reference[M, K], error)

Parse restores a verified credential's stored model reference through the generated codec. Parsing alone grants no authority and performs no lookup.

func (Provider[M, K]) RecheckPassword

func (p Provider[M, K]) RecheckPassword(ctx context.Context, tx *database.Tx, result PasswordResult[M, K]) (M, error)

RecheckPassword locks and returns the current model using the original PasswordLogin binding. It rechecks identity, the verified hash, eligibility and MFA policy without performing a second provider lookup or password hash. A result from a different provider declaration is rejected even when names and model types match. Errors return a zero model.

Call this before factor/credential-store locks in the transaction owning a sensitive password-authorized change. The caller supplies operation capacity, timeout and transaction ownership. Keep the result request-local: this method checks current model state, not a persisted reauthentication ticket's age. PendingMFA results verify only the password stage; an existing second factor is still required where the protected operation demands it.

func (Provider[M, K]) Reference

func (p Provider[M, K]) Reference() model.Reference[M, K]

Reference returns the provider's generated key metadata. A reference is not authentication evidence. Framework adapters reuse it instead of another codec.

func (Provider[M, K]) Resolve

func (p Provider[M, K]) Resolve(ctx context.Context, reference model.Reference[M, K]) (M, error)

Resolve reloads a typed reference and checks current eligibility. This is a server-side lookup, not credential verification or authorization. Missing and ineligible subjects return Unauthenticated. Callers bound its context and own the lifetime; an uncooperative lookup is never abandoned while still running.

func (Provider[M, K]) Validate

func (p Provider[M, K]) Validate() error

Validate checks the name, concrete struct model, lookup, eligibility callback and model reference.

func (Provider[M, K]) ValidateGuard

func (p Provider[M, K]) ValidateGuard(guard Guard[M]) error

ValidateGuard requires the very same provider declaration, not merely matching names. It prevents adapters from pairing a guard with another lookup authority.

type ProviderName

type ProviderName string

ProviderName identifies one authoritative model resolver.

type Registration

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

Registration is the erased assembly boundary, never a dynamic subject lookup. Obtain registrations from typed guards and policies; zero is invalid.

type Registry

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

Registry owns immutable explicit guard/policy declarations and operation capacity. It stores no process-global or cross-request authenticated model.

func NewRegistry

func NewRegistry(c Config, registrations ...Registration) (*Registry, error)

NewRegistry validates configuration and registrations and creates an isolated authentication registry.

func (*Registry) NewScope

func (r *Registry) NewScope(ctx context.Context, credentials Credentials) (*Scope, error)

NewScope creates a cancellable authentication boundary with its own guard-resolution cache. The caller must close the scope.

func (*Registry) Validate

func (r *Registry) Validate() error

Validate checks that the registry is initialized.

func (*Registry) With

func (r *Registry) With(registrations ...Registration) (*Registry, error)

With returns a new immutable registry containing this registry's declarations plus registrations. It shares the receiver's configuration and callback capacity, so derived registries never multiply the application's concurrency bound. Names and provider identities are validated against every inherited declaration; the receiver itself is never modified.

type Revocation

type Revocation[M model.Identifiable, K any] struct {
	// contains filtered or unexported fields
}

Revocation is a typed, explicitly registered credential-store contribution. Framework bindings supply stable names and their original provider declaration. A callback must join tx, use bounded work and never commit or retry. The returned count is provisional until the surrounding transaction commits.

func DefineRevocation

func DefineRevocation[M model.Identifiable, K any](name RevocationName, provider Provider[M, K], revoke func(context.Context, *database.Tx, model.Reference[M, K]) (uint64, error)) Revocation[M, K]

DefineRevocation declares one provider's transactional credential-revocation callback.

func (Revocation[M, K]) Name

func (r Revocation[M, K]) Name() RevocationName

Name returns the revocation target's stable name.

func (Revocation[M, K]) Validate

func (r Revocation[M, K]) Validate() error

Validate checks the name, transactional callback and provider.

type RevocationName

type RevocationName string

RevocationName identifies one stable credential-store contribution.

type Revocations

type Revocations[M model.Identifiable, K any] struct {
	// contains filtered or unexported fields
}

Revocations groups all registered session/token guards for one model provider. It sorts stable target names once, rejects duplicates/provider mismatches and applies every contribution inside one savepoint. Consumers pass Invalidate directly to password reset or other credential-changing domain operations.

func NewRevocations

func NewRevocations[M model.Identifiable, K any](provider Provider[M, K], targets ...Revocation[M, K]) (*Revocations[M, K], error)

NewRevocations copies and orders targets by name, requiring unique names and the exact same provider declaration.

func (*Revocations[M, K]) Invalidate

func (r *Revocations[M, K]) Invalidate(ctx context.Context, tx *database.Tx, subject M) error

Invalidate uses the model's stored identity without checking eligibility: a disabled model must still be revocable. The caller must already hold the model lock and propagate this error. All registered targets use the same order; acquire no model locks after entering a credential-store contribution.

func (*Revocations[M, K]) Validate

func (r *Revocations[M, K]) Validate() error

Validate requires a configured nonempty target group.

type Scope

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

Scope owns credentials and coalesced guard results for one request or explicit authorization boundary. New scopes reverify credentials and load current state. Never retain a scope for a job or a WebSocket connection. Close at its boundary.

func (*Scope) Close

func (s *Scope) Close() error

Close cancels and waits for callbacks started in this scope, then releases credential and model references. It is idempotent. Do not call it from an authentication callback belonging to this scope: that callback must exit first.

func (*Scope) Context

func (s *Scope) Context() context.Context

Context carries this scope's cancellation and private authentication binding. Derive downstream contexts from it; a fresh NewScope replaces inherited authentication state. A zero or nil scope returns nil.

type SecondFactor

type SecondFactor[M model.Identifiable, K any] struct {
	// contains filtered or unexported fields
}

SecondFactor is a typed request-bound verification action, not an authenticated proof. Credential bindings call it within checked creation. A factor adapter must lock the current model, check eligibility, lock its factor, then call the pending-consumption callback once and verify/consume the submitted factor in that SAME transaction. No callback may commit, retry or escape its lifetime. Keep this value within the request; it contains an unverified factor response.

func DefineSecondFactor

func DefineSecondFactor[M model.Identifiable, K any](provider Provider[M, K], verify func(context.Context, *database.Tx, model.Reference[M, K], func(context.Context, *database.Tx) error) error) SecondFactor[M, K]

DefineSecondFactor is a trusted adapter boundary. Applications normally use mfa.Factors.Verifier; defining a callback is not verification of client input.

func (SecondFactor[M, K]) Check

func (s SecondFactor[M, K]) Check(ctx context.Context, tx *database.Tx, provider Provider[M, K], identity model.Identity, consume func(context.Context, *database.Tx) error) error

Check is the transactional credential-adapter boundary. It enforces one consumption callback in the same transaction or a nested savepoint. Omitted, repeated, substituted-transaction or suppressed failures never return success. Transaction correctness remains the adapter's contract; no inspection can undo a dishonest adapter's independently committed writes.

func (SecondFactor[M, K]) Format

func (SecondFactor[M, K]) Format(state fmt.State, _ rune)

Format writes a verification label without exposing factor data.

func (SecondFactor[M, K]) ValidateFor

func (s SecondFactor[M, K]) ValidateFor(provider Provider[M, K]) error

ValidateFor requires a verifier bound to the exact supplied provider declaration.

type Strategy

type Strategy[M, K any] struct {
	// contains filtered or unexported fields
}

Strategy verifies one explicitly selected credential source. Each guard owns its strategy invocation; no implicit fallback from an invalid credential to another strategy occurs. Missing inputs do not call Verify. Omitted results for present inputs mean invalid credentials, not anonymous authentication.

func DefineStrategy

func DefineStrategy[M, K any](source CredentialName, verify func(context.Context, secret.String) (value.Optional[Proof[M, K]], error)) Strategy[M, K]

DefineStrategy declares a verifier for one credential source; missing inputs do not invoke it.

func (Strategy[M, K]) Source

func (s Strategy[M, K]) Source() CredentialName

Source returns the selected credential source.

func (Strategy[M, K]) Validate

func (s Strategy[M, K]) Validate() error

Validate checks the source and verifier, including a bound verifier when binding is enabled.

type TicketRedeemer added in v0.4.0

type TicketRedeemer interface {
	// TicketSource returns the credential source whose tickets this redeemer accepts.
	TicketSource() CredentialName
	// RedeemTicket consumes a single-use handshake ticket, returning omission for unknown,
	// expired or already redeemed tickets.
	RedeemTicket(context.Context, secret.String) (value.Optional[BoundCredential], error)
}

TicketRedeemer exchanges a single-use handshake ticket for a bound credential of the guard whose credential source it names. token.Tokens implements it. An unknown, expired or already redeemed ticket is omitted, not an error.

type Verdict

type Verdict uint8

Verdict is a hook decision. Abstain leaves the declared policy in charge.

const (
	Abstain Verdict = iota
	Allow
	Deny
)

Directories

Path Synopsis
Package challenge owns single-use, model-bound recovery credentials.
Package challenge owns single-use, model-bound recovery credentials.
postgres
Package postgres persists single-use recovery credentials through explicit migrations and generated queries.
Package postgres persists single-use recovery credentials through explicit migrations and generated queries.
Package emailverification binds one-time verification to a concrete model's current stored email.
Package emailverification binds one-time verification to a concrete model's current stored email.
Package lockout provides typed failed-credential windows and temporary lockout.
Package lockout provides typed failed-credential windows and temporary lockout.
memory
Package memory supplies an explicit single-process lockout authority.
Package memory supplies an explicit single-process lockout authority.
mfa
Package mfa owns typed TOTP/recovery factors and model-first factor management.
Package mfa owns typed TOTP/recovery factors and model-first factor management.
command
Package command supplies the explicit MFA key-rotation operation.
Package command supplies the explicit MFA key-rotation operation.
postgres
Package postgres stores encrypted MFA factors through explicit migrations and generated model queries.
Package postgres stores encrypted MFA factors through explicit migrations and generated model queries.
Package oauth is an OAuth 2.0 authorization-code client with PKCE and OpenID Connect ID-token verification for social login.
Package oauth is an OAuth 2.0 authorization-code client with PKCE and OpenID Connect ID-token verification for social login.
Package password provides bounded Argon2id hashing and verification.
Package password provides bounded Argon2id hashing and verification.
Package passwordreset provides typed model-first password recovery.
Package passwordreset provides typed model-first password recovery.
Package session manages opaque, revocable credentials for typed model guards.
Package session manages opaque, revocable credentials for typed model guards.
postgres
Package postgres persists session credentials through Foundry-owned PostgreSQL models and explicit migrations.
Package postgres persists session credentials through Foundry-owned PostgreSQL models and explicit migrations.
Package token manages model-owned personal and renewable access credentials.
Package token manages model-owned personal and renewable access credentials.
postgres
Package postgres implements authoritative token persistence through explicit Foundry migrations and generated model queries.
Package postgres implements authoritative token persistence through explicit Foundry migrations and generated model queries.

Jump to

Keyboard shortcuts

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