flows

package
v0.5.0 Latest Latest
Warning

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

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

Documentation

Overview

Package flows contains pure-function orchestrators for every Engine operation.

Each flow function (RunLogin, RunValidate, RunRefresh, etc.) accepts a typed dependency struct and returns results without side-effects beyond those dependencies. This design enables exhaustive unit testing with mock dependencies and keeps the Engine type thin.

Architecture boundaries

Flow functions coordinate calls to session store, JWT manager, rate limiter, audit dispatcher, and metrics. They do NOT own any of these resources — ownership stays with the Engine.

What this package must NOT do

  • Hold mutable state between calls.
  • Import goAuth (to avoid import cycles).
  • Perform I/O directly — all I/O is mediated through dependency interfaces.

Index

Constants

View Source
const (
	WebAuthnPurposeRegistration byte = 1
	WebAuthnPurposeLogin        byte = 2
)

WebAuthn ceremony purposes (flow-local mirror of the store constants).

View Source
const BackupCodeAlphabet = "ABCDEFGHJKLMNPQRSTUVWXYZ23456789"

Variables

This section is empty.

Functions

func BackupCodeHash

func BackupCodeHash(userID, canonicalCode string) [32]byte

func CanonicalizeBackupCode

func CanonicalizeBackupCode(code string) string

func FormatBackupCode

func FormatBackupCode(code string) string

func NewBackupCode

func NewBackupCode(length int, randomIndex func(int) (int, error)) (string, error)

func ResolveRouteMode

func ResolveRouteMode(routeMode, engineMode int, cfg ModeResolverConfig) (int, bool)

ResolveRouteMode resolves a route mode override against engine default mode.

func RunActiveSessionEstimate

func RunActiveSessionEstimate(ctx context.Context, deps IntrospectionDeps) (int, error)

func RunBeginWebAuthnLogin added in v0.4.0

func RunBeginWebAuthnLogin(ctx context.Context, challengeID string, deps WebAuthnDeps) ([]byte, error)

RunBeginWebAuthnLogin starts the assertion ceremony for a pending MFA login challenge and returns the CredentialRequest options JSON. The ceremony session is keyed by the challenge ID; confirming the login consumes it.

func RunBeginWebAuthnRegistration added in v0.4.0

func RunBeginWebAuthnRegistration(ctx context.Context, userID string, deps WebAuthnDeps) ([]byte, string, error)

RunBeginWebAuthnRegistration starts a credential-registration ceremony for the user and returns the CredentialCreation options JSON plus the ceremony ID the caller must echo back to finish.

func RunConfirmEmailVerification

func RunConfirmEmailVerification(ctx context.Context, challenge string, deps EmailVerificationDeps) error

func RunConfirmEmailVerificationCode

func RunConfirmEmailVerificationCode(ctx context.Context, verificationID, code string, deps EmailVerificationDeps) error

func RunConfirmPasswordResetWithMFA

func RunConfirmPasswordResetWithMFA(ctx context.Context, challenge, newPassword, mfaType, mfaCode string, deps PasswordResetDeps) error

func RunConfirmTOTPSetup

func RunConfirmTOTPSetup(ctx context.Context, userID, code string, deps TOTPDeps) error

func RunConfirmWebAuthnAssertion added in v0.4.0

func RunConfirmWebAuthnAssertion(
	ctx context.Context,
	challengeID string,
	userID string,
	assertionJSON []byte,
	deps WebAuthnDeps,
) error

RunConfirmWebAuthnAssertion verifies an assertion response for the pending login ceremony keyed by challengeID. It consumes the ceremony session (single use), enforces sign-count regression policy, and persists the new sign count. Called from the MFA confirm flow; challenge attempt limiting stays with the caller.

func RunCreateMFALoginChallenge

func RunCreateMFALoginChallenge(ctx context.Context, userID, tenantID string, rememberMe bool, deps LoginDeps) (string, error)

RunCreateMFALoginChallenge creates and stores a new MFA challenge. rememberMe is persisted with the challenge so the durable-session choice made at step 1 survives to token issuance after MFA confirmation.

func RunDisableTOTP

func RunDisableTOTP(ctx context.Context, userID string, deps TOTPDeps) error

func RunFinishWebAuthnRegistration added in v0.4.0

func RunFinishWebAuthnRegistration(
	ctx context.Context,
	userID string,
	ceremonyID string,
	responseJSON []byte,
	deps WebAuthnDeps,
) (*webauthn.Credential, error)

RunFinishWebAuthnRegistration verifies the authenticator's attestation response and returns the credential to persist. The ceremony session is consumed regardless of outcome (single use).

func RunGenerateBackupCodes

func RunGenerateBackupCodes(ctx context.Context, userID string, deps BackupCodeDeps) ([]string, error)

func RunGetActiveSessionCount

func RunGetActiveSessionCount(ctx context.Context, userID string, deps IntrospectionDeps) (int, error)

func RunGetLoginAttempts

func RunGetLoginAttempts(ctx context.Context, identifier string, deps IntrospectionDeps) (int, error)

func RunGetSessionInfo

func RunGetSessionInfo(ctx context.Context, tenantID, sessionID string, deps IntrospectionDeps) (*session.Session, error)

func RunHealth

func RunHealth(ctx context.Context, deps IntrospectionDeps) (bool, time.Duration)

func RunIssueAccountSessionTokens

func RunIssueAccountSessionTokens(ctx context.Context, user AccountUserRecord, rememberMe bool, deps AccountSessionDeps) (string, string, error)

func RunIssueLoginSessionTokens

func RunIssueLoginSessionTokens(
	ctx context.Context,
	username string,
	user LoginUserRecord,
	tenantID string,
	rememberMe bool,
	deps LoginDeps,
) (string, string, error)

RunIssueLoginSessionTokens issues access/refresh tokens after successful login or MFA.

func RunListActiveSessions

func RunListActiveSessions(ctx context.Context, userID string, deps IntrospectionDeps) ([]*session.Session, error)

func RunLogoutAllInTenant

func RunLogoutAllInTenant(ctx context.Context, tenantID, userID string, deps LogoutDeps) error

func RunLogoutInTenant

func RunLogoutInTenant(ctx context.Context, tenantID, sessionID string, deps LogoutDeps) error

func RunRegenerateBackupCodes

func RunRegenerateBackupCodes(ctx context.Context, userID, totpCode string, deps BackupCodeDeps) ([]string, error)

func RunRequestEmailVerification

func RunRequestEmailVerification(ctx context.Context, identifier string, deps EmailVerificationDeps) (string, error)

func RunRequestPasswordReset

func RunRequestPasswordReset(ctx context.Context, identifier string, deps PasswordResetDeps) (string, error)

func RunUpdateAccountStatusAndInvalidate

func RunUpdateAccountStatusAndInvalidate(
	ctx context.Context,
	userID string,
	status uint8,
	deps UpdateAccountStatusDeps,
) error

func RunValidateDeviceBinding

func RunValidateDeviceBinding(ctx context.Context, sess DeviceBindingSession, deps DeviceBindingDeps) error

func RunVerifyBackupCode

func RunVerifyBackupCode(ctx context.Context, userID, code string, deps BackupCodeDeps) error

func RunVerifyBackupCodeInTenant

func RunVerifyBackupCodeInTenant(ctx context.Context, tenantID, userID, code string, deps BackupCodeDeps) error

func RunVerifyTOTP

func RunVerifyTOTP(ctx context.Context, userID, code string, deps TOTPDeps) error

func RunVerifyTOTPForUser

func RunVerifyTOTPForUser(ctx context.Context, user TOTPUser, code string, deps TOTPDeps) error

Types

type AccountCreateRequest

type AccountCreateRequest struct {
	Identifier string
	Password   string
	Role       string
	RememberMe bool
}

type AccountCreateResult

type AccountCreateResult struct {
	UserID       string
	Role         string
	AccessToken  string
	RefreshToken string
}

type AccountCreateUserInput

type AccountCreateUserInput struct {
	Identifier        string
	PasswordHash      string
	Role              string
	TenantID          string
	Status            uint8
	PermissionVersion uint32
	RoleVersion       uint32
	AccountVersion    uint32
}

type AccountDeps

type AccountDeps struct {
	Enabled                  bool
	AutoLogin                bool
	RefreshTTL               time.Duration
	MultiTenantEnabled       bool
	DefaultRole              string
	EmailVerificationEnabled bool
	ShouldRequireVerified    bool
	ActiveStatus             uint8
	PendingStatus            uint8

	TenantIDFromContext         func(context.Context) string
	TenantIDFromContextExplicit func(context.Context) (string, bool)

	EnforceAccountLimiter func(context.Context, string, string) error
	MapLimiterError       func(error) error
	RoleExists            func(string) bool

	HashPassword       func(string) (string, error)
	CreateUser         func(context.Context, AccountCreateUserInput) (AccountUserRecord, error)
	IssueSessionTokens func(context.Context, AccountUserRecord, bool) (string, string, error)

	MetricInc     func(int)
	EmitAudit     func(context.Context, string, bool, string, string, string, error, func() map[string]string)
	EmitRateLimit func(context.Context, string, string, func() map[string]string)

	Metrics AccountMetrics
	Events  AccountEvents
	Errors  AccountErrors
}

type AccountErrors

type AccountErrors struct {
	EngineNotReady              error
	AccountCreationDisabled     error
	AccountCreationUnavailable  error
	AccountCreationInvalid      error
	AccountRoleInvalid          error
	AccountCreationRateLimited  error
	PasswordPolicy              error
	AccountExists               error
	ProviderDuplicateIdentifier error
	SessionCreationFailed       error
}

type AccountEvents

type AccountEvents struct {
	AccountCreationSuccess     string
	AccountCreationFailure     string
	AccountCreationDuplicate   string
	AccountCreationRateLimited string
}

type AccountMetrics

type AccountMetrics struct {
	AccountCreationSuccess     int
	AccountCreationDuplicate   int
	AccountCreationRateLimited int
}

type AccountSessionDeps

type AccountSessionDeps struct {
	TenantIDFromContext func(context.Context) string
	Now                 func() time.Time
	SessionLifetime     func(rememberMe bool) time.Duration

	GetRoleMask        func(string) (interface{}, bool)
	NewSessionID       func() (string, error)
	NewRefreshSecret   func() ([32]byte, error)
	HashRefreshSecret  func([32]byte) [32]byte
	EncodeRefreshToken func(string, [32]byte) (string, error)
	SaveSession        func(context.Context, *session.Session, time.Duration) error
	IssueAccessToken   func(*session.Session) (string, error)

	MetricInc            func(int)
	SessionCreatedMetric int

	ErrEngineNotReady     error
	ErrAccountRoleInvalid error
}

type AccountStatusRecord

type AccountStatusRecord struct {
	Status         uint8
	AccountVersion uint32
	TenantID       string
}

type AccountUserRecord

type AccountUserRecord struct {
	UserID            string
	Identifier        string
	TenantID          string
	PasswordHash      string
	Status            uint8
	Role              string
	PermissionVersion uint32
	RoleVersion       uint32
	AccountVersion    uint32
}

type BackupCodeDeps

type BackupCodeDeps struct {
	Enabled          bool
	BackupCodeCount  int
	BackupCodeLength int

	TenantIDFromContext func(context.Context) string
	AccountStatusError  func(uint8) error

	GetUserByID        func(context.Context, string) (BackupCodeUser, error)
	GetBackupCodes     func(context.Context, string) ([]BackupCodeRecord, error)
	ReplaceBackupCodes func(context.Context, string, []BackupCodeRecord) error
	ConsumeBackupCode  func(context.Context, string, [32]byte) (bool, error)
	VerifyTOTPForUser  func(context.Context, BackupCodeUser, string) error

	CheckLimiter         func(context.Context, string, string) error
	RecordLimiterFailure func(context.Context, string, string) error
	ResetLimiter         func(context.Context, string, string) error
	IsRateLimited        func(error) bool

	RandomIndex func(int) (int, error)

	MetricInc func(int)
	EmitAudit func(context.Context, string, bool, string, string, string, error, func() map[string]string)

	Metrics BackupCodeMetrics
	Events  BackupCodeEvents
	Errors  BackupCodeErrors
}

type BackupCodeErrors

type BackupCodeErrors struct {
	TOTPFeatureDisabled                error
	EngineNotReady                     error
	UserNotFound                       error
	BackupCodeUnavailable              error
	BackupCodeRegenerationRequiresTOTP error
	BackupCodeInvalid                  error
	BackupCodeRateLimited              error
}

type BackupCodeEvents

type BackupCodeEvents struct {
	BackupCodesGenerated string
	BackupCodeUsed       string
	BackupCodeFailed     string
}

type BackupCodeMetrics

type BackupCodeMetrics struct {
	BackupCodeUsed        int
	BackupCodeFailed      int
	BackupCodeRegenerated int
}

type BackupCodeRecord

type BackupCodeRecord struct {
	Hash [32]byte
}

type BackupCodeUser

type BackupCodeUser struct {
	UserID   string
	TenantID string
	Status   uint8
}

type Deps

type Deps struct {
	Refresh           RefreshDeps
	Validate          ValidateDeps
	Logout            LogoutDeps
	Introspection     IntrospectionDeps
	Account           AccountDeps
	AccountSession    AccountSessionDeps
	AccountStatus     UpdateAccountStatusDeps
	BackupCode        BackupCodeDeps
	DeviceBinding     DeviceBindingDeps
	EmailVerification EmailVerificationDeps
	Login             LoginDeps
	PasswordReset     PasswordResetDeps
	TOTP              TOTPDeps
	WebAuthn          WebAuthnDeps
}

Deps groups flow dependency sets. Root engine builds this once and delegates request methods to the matching flow implementation.

type DeviceBindingConfig

type DeviceBindingConfig struct {
	Enabled                 bool
	EnforceIPBinding        bool
	DetectIPChange          bool
	EnforceUserAgentBinding bool
	DetectUserAgentChange   bool
}

type DeviceBindingDeps

type DeviceBindingDeps struct {
	Config                     DeviceBindingConfig
	ClientIPFromContext        func(context.Context) string
	UserAgentFromContext       func(context.Context) string
	HashBindingValue           func(string) [32]byte
	ShouldEmitDeviceAnomaly    func(context.Context, string, string) bool
	MetricInc                  func(int)
	EmitAudit                  func(context.Context, string, bool, string, string, string, error, func() map[string]string)
	EventDeviceAnomalyDetected string
	EventDeviceBindingRejected string
	MetricDeviceIPMismatch     int
	MetricDeviceUAMismatch     int
	MetricDeviceRejected       int
	ErrDeviceBindingRejected   error
}

type DeviceBindingSession

type DeviceBindingSession struct {
	SessionID     string
	UserID        string
	TenantID      string
	IPHash        [32]byte
	UserAgentHash [32]byte
}

type EmailVerificationDeps

type EmailVerificationDeps struct {
	Enabled         bool
	Strategy        int
	OTPDigits       int
	VerificationTTL time.Duration
	MaxAttempts     int
	ActiveStatus    uint8

	TenantIDFromContext func(context.Context) string
	AccountStatusError  func(uint8) error
	Now                 func() time.Time

	CheckRequestLimiter func(context.Context, string, string) error
	CheckConfirmLimiter func(context.Context, string, string) error
	MapLimiterError     func(error) error
	MapStoreError       func(error) error

	// EnforceTenantMatch requires a resolved user's TenantID to equal the
	// request's tenant. Set only when multi-tenancy is enabled.
	EnforceTenantMatch bool

	Warn func(string, ...any)

	// GetUserByIdentifier takes a context so the engine can scope the
	// lookup to the request's tenant when multi-tenancy is on.
	GetUserByIdentifier func(context.Context, string) (EmailVerificationUser, error)

	// GetUserByIDInTenant scopes the lookup to an explicitly supplied
	// tenant rather than the request context's. Confirm paths pass the
	// tenant the verification record was loaded under, which for
	// token/UUID challenges comes from the challenge itself and is
	// authoritative — the context tenant may be absent or different.
	GetUserByIDInTenant func(ctx context.Context, tenantID, userID string) (EmailVerificationUser, error)

	// WithTenant returns ctx carrying tenantID as the request tenant. The
	// confirm paths use it to propagate the challenge's authoritative
	// tenant into downstream operations that read the tenant from context.
	WithTenant func(ctx context.Context, tenantID string) context.Context

	UpdateStatusAndInvalidate func(context.Context, string, uint8) error

	SaveVerificationRecord    func(context.Context, string, string, EmailVerificationStoreRecord, time.Duration) error
	ConsumeVerificationRecord func(context.Context, string, string, [32]byte, int, int) (EmailVerificationStoreRecord, error)

	GenerateChallenge     func(int, int, string) (string, string, [32]byte, error)
	ParseChallenge        func(int, string, int) (string, string, [32]byte, error)
	ParseChallengeCode    func(int, string, string, int) ([32]byte, error)
	SleepEnumerationDelay func(context.Context) error

	MetricInc     func(int)
	EmitAudit     func(context.Context, string, bool, string, string, string, error, func() map[string]string)
	EmitRateLimit func(context.Context, string, string, func() map[string]string)

	Metrics EmailVerificationMetrics
	Events  EmailVerificationEvents
	Errors  EmailVerificationErrors
}

type EmailVerificationErrors

type EmailVerificationErrors struct {
	EngineNotReady               error
	EmailVerificationDisabled    error
	EmailVerificationInvalid     error
	EmailVerificationRateLimited error
	EmailVerificationUnavailable error
	EmailVerificationAttempts    error
	UserNotFound                 error
}

type EmailVerificationEvents

type EmailVerificationEvents struct {
	EmailVerificationRequest string
	EmailVerificationConfirm string
}

type EmailVerificationMetrics

type EmailVerificationMetrics struct {
	EmailVerificationRequest          int
	EmailVerificationSuccess          int
	EmailVerificationFailure          int
	EmailVerificationAttemptsExceeded int
}

type EmailVerificationStoreRecord

type EmailVerificationStoreRecord struct {
	UserID     string
	SecretHash [32]byte
	ExpiresAt  int64
	Attempts   uint16
	Strategy   int
}

type EmailVerificationUser

type EmailVerificationUser struct {
	UserID   string
	TenantID string
	Status   uint8
}

type IntrospectionDeps

type IntrospectionDeps struct {
	SessionStore                IntrospectionSessionStore
	RateLimiter                 IntrospectionRateLimiter
	MultiTenantEnabled          bool
	TenantIDFromContext         func(context.Context) string
	TenantIDFromContextExplicit func(context.Context) (string, bool)
	UnauthorizedErr             error
	EngineNotReadyErr           error
	UserNotFoundErr             error
	SessionNotFoundErr          error
	RedisNil                    error
}

type IntrospectionRateLimiter

type IntrospectionRateLimiter interface {
	GetLoginAttempts(ctx context.Context, tenantID, identifier string) (int, error)
}

type IntrospectionSessionStore

type IntrospectionSessionStore interface {
	ActiveSessionCount(ctx context.Context, tenantID, userID string) (int, error)
	ActiveSessionIDs(ctx context.Context, tenantID, userID string) ([]string, error)
	GetManyReadOnly(ctx context.Context, tenantID string, sessionIDs []string) ([]*session.Session, error)
	GetReadOnly(ctx context.Context, tenantID, sessionID string) (*session.Session, error)
	EstimateActiveSessions(ctx context.Context, tenantID string) (int, error)
	Ping(ctx context.Context) (time.Duration, error)
}

type LoginDeps

type LoginDeps struct {
	TOTPEnabled               bool
	RequireTOTPForLogin       bool
	WebAuthnEnabled           bool
	WebAuthnRequireForLogin   bool
	EnforceReplayProtection   bool
	RequireVerified           bool
	PendingVerificationStatus uint8
	PasswordUpgradeOnLogin    bool
	MFALoginMaxAttempts       int
	MFALoginChallengeTTL      time.Duration
	DeviceBindingEnabled      bool
	EnforceIPBinding          bool
	EnforceUserAgentBinding   bool

	TenantIDFromContext  func(context.Context) string
	ClientIPFromContext  func(context.Context) string
	UserAgentFromContext func(context.Context) string
	Now                  func() time.Time
	AccountStatusError   func(status uint8) error

	CheckLoginRate     func(context.Context, string) error
	IncrementLoginRate func(context.Context, string) error
	ResetLoginRate     func(context.Context, string) error

	// Auto-lockout hooks: RecordLockoutFailure returns true when threshold is reached.
	AutoLockoutEnabled   bool
	RecordLockoutFailure func(context.Context, string) (bool, error)
	ResetLockoutCounter  func(context.Context, string) error
	LockAccount          func(context.Context, string) error

	// EnforceTenantMatch requires a resolved user's TenantID to equal the
	// request's tenant. Set only when multi-tenancy is enabled; with it
	// false the flow behaves exactly as it did before tenant scoping.
	EnforceTenantMatch bool

	// GetUserByIdentifier and GetUserByID take a context so the engine can
	// scope the lookup to the request's tenant when multi-tenancy is on.
	GetUserByIdentifier       func(context.Context, string) (LoginUserRecord, error)
	GetUserByID               func(context.Context, string) (LoginUserRecord, error)
	UpdatePasswordHash        func(string, string) error
	GetTOTPSecret             func(context.Context, string) (*LoginTOTPRecord, error)
	UpdateTOTPLastUsedCounter func(context.Context, string, int64) error

	VerifyPassword           func(string, string) (bool, error)
	PasswordNeedsUpgrade     func(string) (bool, error)
	HashPassword             func(string) (string, error)
	VerifyTOTPCode           func([]byte, string, time.Time) (bool, int64, error)
	VerifyBackupCodeInTenant func(context.Context, string, string, string) error

	GetMFAChallenge    func(context.Context, string) (*MFALoginChallengeRecord, error)
	SaveMFAChallenge   func(context.Context, string, *MFALoginChallengeRecord, time.Duration) error
	DeleteMFAChallenge func(context.Context, string) (bool, error)
	RecordMFAFailure   func(context.Context, string, int) (bool, error)
	MapMFAStoreError   func(error) error

	CreateMFALoginChallenge func(context.Context, string, string, bool) (string, error)
	IssueLoginSessionTokens func(context.Context, string, LoginUserRecord, string, bool) (string, string, error)
	EnforceSessionHardening func(context.Context, string, string) error

	// WebAuthn second-factor hooks (nil when the feature is disabled).
	HasWebAuthnCredentials   func(context.Context, string) (bool, error)
	ConfirmWebAuthnAssertion func(context.Context, string, string, []byte) error

	GetRoleMask        func(string) (interface{}, bool)
	NewSessionID       func() (string, error)
	NewRefreshSecret   func() ([32]byte, error)
	HashRefreshSecret  func([32]byte) [32]byte
	EncodeRefreshToken func(string, [32]byte) (string, error)
	HashBindingValue   func(string) [32]byte
	SessionLifetime    func(rememberMe bool) time.Duration
	SaveSession        func(context.Context, *session.Session, time.Duration) error
	IssueAccessToken   func(*session.Session) (string, error)

	MetricInc     func(int)
	EmitAudit     func(context.Context, string, bool, string, string, string, error, func() map[string]string)
	EmitRateLimit func(context.Context, string, string, func() map[string]string)
	Warn          func(string, ...any)

	Metrics LoginMetrics
	Events  LoginEvents
	Errors  LoginErrors
}

LoginDeps captures login+mfa dependencies.

type LoginErrors

type LoginErrors struct {
	EngineNotReady           error
	InvalidCredentials       error
	LoginRateLimited         error
	AccountUnverified        error
	AccountLocked            error
	DeviceBindingRejected    error
	TOTPFeatureDisabled      error
	MFALoginInvalid          error
	MFALoginExpired          error
	MFALoginAttemptsExceeded error
	MFALoginReplay           error
	MFALoginUnavailable      error
	UserNotFound             error
	BackupCodeRateLimited    error
	BackupCodeInvalid        error
	BackupCodesNotConfigured error
	WebAuthnCloneDetected    error
	WebAuthnCeremonyExpired  error
	WebAuthnUnavailable      error
}

LoginErrors carries host-level sentinel errors used by login/mfa flows.

type LoginEvents

type LoginEvents struct {
	LoginSuccess        string
	LoginFailure        string
	LoginRateLimited    string
	MFARequired         string
	MFASuccess          string
	MFAFailure          string
	MFAAttemptsExceeded string
}

LoginEvents carries audit event names used by login/mfa flows.

type LoginMetrics

type LoginMetrics struct {
	LoginSuccess     int
	LoginFailure     int
	LoginRateLimited int
	LockoutTrigger   int
	SessionCreated   int
	MFALoginRequired int
	MFALoginSuccess  int
	MFALoginFailure  int
	MFAReplayAttempt int
}

LoginMetrics carries metric IDs needed by login/mfa flows.

type LoginOptions added in v0.4.0

type LoginOptions struct {
	RememberMe bool
}

LoginOptions carries per-login options threaded from the public API.

type LoginResult

type LoginResult struct {
	AccessToken  string
	RefreshToken string
	MFARequired  bool
	MFAType      string
	MFASession   string
	MFATypes     []string
}

LoginResult is the flow-local login response shape.

func RunConfirmLoginMFAWithType

func RunConfirmLoginMFAWithType(ctx context.Context, challengeID, code, mfaType string, deps LoginDeps) (*LoginResult, error)

RunConfirmLoginMFAWithType executes MFA challenge confirmation and session issuance.

func RunLoginWithResult

func RunLoginWithResult(ctx context.Context, username, password string, opts LoginOptions, deps LoginDeps) (*LoginResult, error)

RunLoginWithResult executes the login flow and either issues tokens or returns MFA challenge details.

type LoginTOTPRecord

type LoginTOTPRecord struct {
	Secret          []byte
	Enabled         bool
	LastUsedCounter int64
}

LoginTOTPRecord is a flow-local TOTP provider record.

type LoginUserRecord

type LoginUserRecord struct {
	UserID            string
	Identifier        string
	TenantID          string
	PasswordHash      string
	Role              string
	Status            uint8
	PermissionVersion uint32
	RoleVersion       uint32
	AccountVersion    uint32
}

LoginUserRecord is a flow-local user model used by login/mfa flows.

type LogoutByAccessResult

type LogoutByAccessResult struct {
	TenantID  string
	SessionID string
	// TokenExpired reports that the access token was expired but otherwise
	// authentic; surfaced as audit metadata, not as an error.
	TokenExpired bool
	Err          error
}

func RunLogoutByAccessToken

func RunLogoutByAccessToken(ctx context.Context, tokenStr string, deps LogoutDeps) LogoutByAccessResult

type LogoutDeps

type LogoutDeps struct {
	// ParseAccessAllowExpired accepts authentic tokens whose only defect is
	// expiry, so an expired session can still be logged out gracefully.
	ParseAccessAllowExpired func(string) (*jwt.AccessClaims, error)
	TenantIDFromContext     func(context.Context) string
	TenantIDFromToken       func(string) string
	Now                     func() time.Time
	SessionStore            LogoutSessionStore
}

LogoutDeps captures logout flow dependencies.

type LogoutSessionStore

type LogoutSessionStore interface {
	Delete(ctx context.Context, tenantID, sessionID string) error
	DeleteAllForUser(ctx context.Context, tenantID, userID string) error
}

type MFALoginChallengeRecord

type MFALoginChallengeRecord struct {
	UserID     string
	TenantID   string
	ExpiresAt  int64
	Attempts   uint16
	RememberMe bool
}

MFALoginChallengeRecord is a flow-local MFA challenge record.

type ModeResolverConfig

type ModeResolverConfig struct {
	ModeInherit int
	ModeJWTOnly int
	ModeHybrid  int
	ModeStrict  int
}

ModeResolverConfig allows host packages to resolve route/engine validation modes without importing host package-specific enums (avoids import cycles).

type PasswordResetDeps

type PasswordResetDeps struct {
	Enabled     bool
	Strategy    int
	OTPDigits   int
	ResetTTL    time.Duration
	MaxAttempts int
	RequireMFA  bool

	TenantIDFromContext func(context.Context) string
	AccountStatusError  func(uint8) error
	Now                 func() time.Time

	CheckRequestLimiter func(context.Context, string, string) error
	CheckConfirmLimiter func(context.Context, string, string) error
	MapLimiterError     func(error) error
	MapStoreError       func(error) error
	IsStoreNotFound     func(error) bool

	// EnforceTenantMatch requires a resolved user's TenantID to equal the
	// request's tenant. Set only when multi-tenancy is enabled.
	EnforceTenantMatch bool

	Warn func(string, ...any)

	// GetUserByIdentifier and GetUserByID take a context so the engine can
	// scope the lookup to the request's tenant when multi-tenancy is on.
	GetUserByIdentifier func(context.Context, string) (PasswordResetUser, error)
	GetUserByID         func(context.Context, string) (PasswordResetUser, error)
	HashPassword        func(string) (string, error)
	UpdatePasswordHash  func(string, string) error
	LogoutAllInTenant   func(context.Context, string, string) error

	SaveResetRecord    func(context.Context, string, string, PasswordResetStoreRecord, time.Duration) error
	GetResetRecord     func(context.Context, string, string) (PasswordResetStoreRecord, error)
	ConsumeResetRecord func(context.Context, string, string, [32]byte, int, int) (PasswordResetStoreRecord, error)

	GenerateChallenge     func(int, int) (string, string, [32]byte, error)
	ParseChallenge        func(int, string, int) (string, [32]byte, error)
	SleepEnumerationDelay func(context.Context) error

	VerifyTOTPForUser        func(context.Context, PasswordResetUser, string) error
	VerifyBackupCodeInTenant func(context.Context, string, string, string) error

	MetricInc     func(int)
	EmitAudit     func(context.Context, string, bool, string, string, string, error, func() map[string]string)
	EmitRateLimit func(context.Context, string, string, func() map[string]string)

	Metrics PasswordResetMetrics
	Events  PasswordResetEvents
	Errors  PasswordResetErrors
}

type PasswordResetErrors

type PasswordResetErrors struct {
	EngineNotReady            error
	PasswordResetDisabled     error
	PasswordResetInvalid      error
	PasswordResetRateLimited  error
	PasswordResetUnavailable  error
	PasswordResetAttempts     error
	PasswordPolicy            error
	UserNotFound              error
	SessionInvalidationFailed error
	TOTPInvalid               error
}

type PasswordResetEvents

type PasswordResetEvents struct {
	PasswordResetRequest string
	PasswordResetConfirm string
	PasswordResetReplay  string
}

type PasswordResetMetrics

type PasswordResetMetrics struct {
	PasswordResetRequest          int
	PasswordResetConfirmSuccess   int
	PasswordResetConfirmFailure   int
	PasswordResetAttemptsExceeded int
}

type PasswordResetStoreRecord

type PasswordResetStoreRecord struct {
	UserID     string
	SecretHash [32]byte
	ExpiresAt  int64
	Attempts   uint16
	Strategy   int
}

type PasswordResetUser

type PasswordResetUser struct {
	UserID   string
	TenantID string
	Status   uint8
}

type RefreshDeps

type RefreshDeps struct {
	TenantIDFromContext       func(context.Context) string
	DecodeRefreshToken        func(string) (string, [32]byte, error)
	NewRefreshSecret          func() ([32]byte, error)
	HashRefreshSecret         func([32]byte) [32]byte
	EncodeRefreshToken        func(string, [32]byte) (string, error)
	IssueAccessToken          func(*session.Session) (string, error)
	AccountStatusError        func(uint8) error
	ShouldRequireVerified     func() bool
	PendingVerificationStatus uint8
	SessionLifetime           func() time.Duration
	EnableReplayTracking      bool
	Warn                      func(string, ...any)
	SessionStore              RefreshSessionStore
	RefreshHashMismatch       error
	RedisNil                  error
}

RefreshDeps captures refresh flow dependencies.

type RefreshFailureKind

type RefreshFailureKind int

RefreshFailureKind classifies refresh flow failures for root-level mapping.

const (
	RefreshFailureNone RefreshFailureKind = iota
	RefreshFailureDecode
	RefreshFailureNextSecret
	RefreshFailureReuse
	RefreshFailureSessionNotFound
	RefreshFailureRotate
	RefreshFailureAccountStatus
	RefreshFailureUnverified
	RefreshFailureIssueAccess
	RefreshFailureEncode
)

type RefreshResult

type RefreshResult struct {
	Failure      RefreshFailureKind
	Err          error
	TenantID     string
	SessionID    string
	UserID       string
	Session      *session.Session
	AccessToken  string
	RefreshToken string
}

RefreshResult carries either the issued token pair or failure metadata.

func RunRefresh

func RunRefresh(ctx context.Context, refreshToken string, deps RefreshDeps) RefreshResult

RunRefresh executes refresh rotation and issuance logic without root package dependencies.

type RefreshSessionStore

type RefreshSessionStore interface {
	RotateRefreshHash(
		ctx context.Context,
		tenantID, sessionID string,
		providedHash [32]byte,
		nextHash [32]byte,
	) (*session.Session, error)
	TrackReplayAnomaly(ctx context.Context, sessionID string, ttl time.Duration) error
	Delete(ctx context.Context, tenantID, sessionID string) error
}

type Service

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

Service is the centralized flow runner built once by the root engine.

func New

func New(deps Deps) Service

New returns a flow service with immutable dependency wiring.

func (Service) ActiveSessionEstimate

func (s Service) ActiveSessionEstimate(ctx context.Context) (int, error)

func (Service) BeginWebAuthnLogin added in v0.4.0

func (s Service) BeginWebAuthnLogin(ctx context.Context, challengeID string) ([]byte, error)

func (Service) BeginWebAuthnRegistration added in v0.4.0

func (s Service) BeginWebAuthnRegistration(ctx context.Context, userID string) ([]byte, string, error)

func (Service) ConfirmEmailVerification

func (s Service) ConfirmEmailVerification(ctx context.Context, challenge string) error

func (Service) ConfirmEmailVerificationCode

func (s Service) ConfirmEmailVerificationCode(ctx context.Context, verificationID, code string) error

func (Service) ConfirmLoginMFAWithType

func (s Service) ConfirmLoginMFAWithType(ctx context.Context, challengeID, code, mfaType string) (*LoginResult, error)

func (Service) ConfirmPasswordResetWithMFA

func (s Service) ConfirmPasswordResetWithMFA(ctx context.Context, challenge, newPassword, mfaType, mfaCode string) error

func (Service) ConfirmTOTPSetup

func (s Service) ConfirmTOTPSetup(ctx context.Context, userID, code string) error

func (Service) ConfirmWebAuthnAssertion added in v0.4.0

func (s Service) ConfirmWebAuthnAssertion(ctx context.Context, challengeID, userID string, assertionJSON []byte) error

func (Service) CreateAccount

func (s Service) CreateAccount(ctx context.Context, req AccountCreateRequest) (*AccountCreateResult, error)

func (Service) CreateMFALoginChallenge

func (s Service) CreateMFALoginChallenge(ctx context.Context, userID, tenantID string, rememberMe bool) (string, error)

func (Service) DisableTOTP

func (s Service) DisableTOTP(ctx context.Context, userID string) error

func (Service) FinishWebAuthnRegistration added in v0.4.0

func (s Service) FinishWebAuthnRegistration(ctx context.Context, userID, ceremonyID string, responseJSON []byte) (*webauthn.Credential, error)

func (Service) GenerateBackupCodes

func (s Service) GenerateBackupCodes(ctx context.Context, userID string) ([]string, error)

func (Service) GenerateTOTPSetup

func (s Service) GenerateTOTPSetup(ctx context.Context, userID string) (*TOTPSetup, error)

func (Service) GetActiveSessionCount

func (s Service) GetActiveSessionCount(ctx context.Context, userID string) (int, error)

func (Service) GetLoginAttempts

func (s Service) GetLoginAttempts(ctx context.Context, identifier string) (int, error)

func (Service) GetSessionInfo

func (s Service) GetSessionInfo(ctx context.Context, tenantID, sessionID string) (*session.Session, error)

func (Service) Health

func (s Service) Health(ctx context.Context) (bool, time.Duration)

func (Service) Initialized

func (s Service) Initialized() bool

Initialized reports whether the service has been wired with flow deps.

func (Service) IssueAccountSessionTokens

func (s Service) IssueAccountSessionTokens(ctx context.Context, user AccountUserRecord, rememberMe bool) (string, string, error)

func (Service) IssueLoginSessionTokens

func (s Service) IssueLoginSessionTokens(
	ctx context.Context,
	username string,
	user LoginUserRecord,
	tenantID string,
	rememberMe bool,
) (string, string, error)

func (Service) ListActiveSessions

func (s Service) ListActiveSessions(ctx context.Context, userID string) ([]*session.Session, error)

func (Service) LoginWithResult

func (s Service) LoginWithResult(ctx context.Context, username, password string, opts LoginOptions) (*LoginResult, error)

func (Service) LogoutAllInTenant

func (s Service) LogoutAllInTenant(ctx context.Context, tenantID, userID string) error

func (Service) LogoutByAccessToken

func (s Service) LogoutByAccessToken(ctx context.Context, tokenStr string) LogoutByAccessResult

func (Service) LogoutInTenant

func (s Service) LogoutInTenant(ctx context.Context, tenantID, sessionID string) error

func (Service) ProvisionTOTP

func (s Service) ProvisionTOTP(ctx context.Context, userID string) (*TOTPProvision, error)

func (Service) Refresh

func (s Service) Refresh(ctx context.Context, refreshToken string) RefreshResult

func (Service) RegenerateBackupCodes

func (s Service) RegenerateBackupCodes(ctx context.Context, userID, totpCode string) ([]string, error)

func (Service) RequestEmailVerification

func (s Service) RequestEmailVerification(ctx context.Context, identifier string) (string, error)

func (Service) RequestPasswordReset

func (s Service) RequestPasswordReset(ctx context.Context, identifier string) (string, error)

func (Service) UpdateAccountStatusAndInvalidate

func (s Service) UpdateAccountStatusAndInvalidate(ctx context.Context, userID string, status uint8) error

func (Service) Validate

func (s Service) Validate(ctx context.Context, tokenStr string, routeMode int) ValidateResult

func (Service) ValidateDeviceBinding

func (s Service) ValidateDeviceBinding(ctx context.Context, sess DeviceBindingSession) error

func (Service) VerifyBackupCode

func (s Service) VerifyBackupCode(ctx context.Context, userID, code string) error

func (Service) VerifyBackupCodeInTenant

func (s Service) VerifyBackupCodeInTenant(ctx context.Context, tenantID, userID, code string) error

func (Service) VerifyTOTP

func (s Service) VerifyTOTP(ctx context.Context, userID, code string) error

func (Service) VerifyTOTPForUser

func (s Service) VerifyTOTPForUser(ctx context.Context, user TOTPUser, code string) error

type TOTPDeps

type TOTPDeps struct {
	Enabled                 bool
	EnforceReplayProtection bool

	Now                 func() time.Time
	TenantIDFromContext func(context.Context) string
	AccountStatusError  func(uint8) error

	GetUserByID               func(context.Context, string) (TOTPUser, error)
	GetTOTPSecret             func(context.Context, string) (*TOTPRecord, error)
	EnableTOTP                func(context.Context, string, []byte) error
	DisableTOTP               func(context.Context, string) error
	MarkTOTPVerified          func(context.Context, string) error
	UpdateTOTPLastUsedCounter func(context.Context, string, int64) error
	LogoutAllInTenant         func(context.Context, string, string) error

	GenerateSecret func() ([]byte, string, error)
	ProvisionURI   func(string, string) string
	VerifyCode     func([]byte, string, time.Time) (bool, int64, error)

	CheckTOTPLimiter         func(context.Context, string) error
	RecordTOTPLimiterFailure func(context.Context, string) error
	ResetTOTPLimiter         func(context.Context, string) error
	IsTOTPRateLimited        func(error) bool

	MetricInc func(int)
	EmitAudit func(context.Context, string, bool, string, string, string, error, func() map[string]string)

	Metrics TOTPMetrics
	Events  TOTPEvents
	Errors  TOTPErrors
}

type TOTPErrors

type TOTPErrors struct {
	TOTPFeatureDisabled       error
	EngineNotReady            error
	UserNotFound              error
	TOTPUnavailable           error
	TOTPNotConfigured         error
	TOTPRequired              error
	TOTPInvalid               error
	TOTPRateLimited           error
	AccountVersionNotAdvanced error
	SessionInvalidationFailed error
}

type TOTPEvents

type TOTPEvents struct {
	TOTPSetupRequested string
	TOTPEnabled        string
	TOTPDisabled       string
	TOTPFailure        string
	TOTPSuccess        string
}

type TOTPMetrics

type TOTPMetrics struct {
	TOTPRequired int
	TOTPFailure  int
	TOTPSuccess  int
}

type TOTPProvision

type TOTPProvision struct {
	Secret string
	URI    string
}

func RunProvisionTOTP

func RunProvisionTOTP(ctx context.Context, userID string, deps TOTPDeps) (*TOTPProvision, error)

type TOTPRecord

type TOTPRecord struct {
	Secret          []byte
	Enabled         bool
	LastUsedCounter int64
}

type TOTPSetup

type TOTPSetup struct {
	SecretBase32 string
	QRCodeURL    string
}

func RunGenerateTOTPSetup

func RunGenerateTOTPSetup(ctx context.Context, userID string, deps TOTPDeps) (*TOTPSetup, error)

type TOTPUser

type TOTPUser struct {
	UserID         string
	Identifier     string
	TenantID       string
	Status         uint8
	AccountVersion uint32
}

type UpdateAccountStatusDeps

type UpdateAccountStatusDeps struct {
	GetUserByID                  func(ctx context.Context, userID string) (AccountStatusRecord, error)
	UpdateAccountStatus          func(ctx context.Context, userID string, status uint8) (AccountStatusRecord, error)
	LogoutAllInTenant            func(ctx context.Context, tenantID, userID string) error
	TenantIDFromContext          func(context.Context) string
	ErrEngineNotReady            error
	ErrUserNotFound              error
	ErrAccountVersionNotAdvanced error
	ErrUnauthorized              error
	ErrSessionInvalidationFailed error
}

type ValidateDeps

type ValidateDeps struct {
	ParseAccess               func(string) (*jwt.AccessClaims, error)
	ResolveRouteMode          func(int) (int, error)
	Now                       func() time.Time
	MaxClockSkew              time.Duration
	ModeJWTOnly               int
	ModeHybrid                int
	EnablePermissionCheck     bool
	EnableRoleCheck           bool
	EnableAccountCheck        bool
	ShouldRequireVerified     func() bool
	PendingVerificationStatus uint8
	AccountStatusError        func(uint8) error
	ValidateDeviceBinding     func(context.Context, *session.Session) error
	TenantIDFromToken         func(string) string
	SessionLifetime           func() time.Duration
	SessionStore              ValidateSessionStore
	RedisUnavailable          error
	RedisNil                  error
}

ValidateDeps captures strict/hybrid/jwt-only validation dependencies.

type ValidateFailureKind

type ValidateFailureKind int

ValidateFailureKind classifies validation failures for root-level mapping.

const (
	ValidateFailureNone ValidateFailureKind = iota
	ValidateFailureUnauthorized
	ValidateFailureTokenClockSkew
	ValidateFailureInvalidRouteMode
	ValidateFailureSessionNotFound
	ValidateFailureStatus
	ValidateFailureUnverified
	ValidateFailureDeviceBinding
)

type ValidateResult

type ValidateResult struct {
	Failure ValidateFailureKind
	Err     error
	Claims  *jwt.AccessClaims
	Session *session.Session
}

ValidateResult returns either claims/session success payload or classified failure.

func RunValidate

func RunValidate(ctx context.Context, tokenStr string, routeMode int, deps ValidateDeps) ValidateResult

RunValidate executes access-token validation and strict-session checks.

type ValidateSessionStore

type ValidateSessionStore interface {
	Get(ctx context.Context, tenantID, sessionID string, ttl time.Duration) (*session.Session, error)
	Delete(ctx context.Context, tenantID, sessionID string) error
}

type WebAuthnDeps added in v0.4.0

type WebAuthnDeps struct {
	Enabled                    bool
	RequireForLogin            bool
	RejectClonedAuthenticators bool
	CeremonyTTL                time.Duration

	WebAuthn *webauthn.WebAuthn

	TenantIDFromContext func(context.Context) string
	Now                 func() time.Time
	NewCeremonyID       func() (string, error)

	GetUserByID               func(context.Context, string) (LoginUserRecord, error)
	GetCredentials            func(context.Context, string) ([]webauthn.Credential, error)
	AddCredential             func(context.Context, string, webauthn.Credential) error
	UpdateCredentialSignCount func(context.Context, string, []byte, uint32) error

	SaveSession          func(context.Context, string, *WebAuthnSessionRecord, time.Duration) error
	ConsumeSession       func(context.Context, string) (*WebAuthnSessionRecord, error)
	MapSessionStoreError func(error) error

	GetMFAChallenge  func(context.Context, string) (*MFALoginChallengeRecord, error)
	MapMFAStoreError func(error) error

	MetricInc func(int)
	EmitAudit func(context.Context, string, bool, string, string, string, error, func() map[string]string)

	Events WebAuthnEvents
	Errors WebAuthnErrors
}

WebAuthnDeps captures WebAuthn ceremony dependencies.

type WebAuthnErrors added in v0.4.0

type WebAuthnErrors struct {
	EngineNotReady     error
	Disabled           error
	Invalid            error
	CeremonyExpired    error
	CloneDetected      error
	CredentialNotFound error
	Unavailable        error
	UserNotFound       error
}

WebAuthnErrors carries host-level sentinel errors used by WebAuthn flows.

type WebAuthnEvents added in v0.4.0

type WebAuthnEvents struct {
	RegisterSuccess string
	RegisterFailure string
}

WebAuthnEvents carries audit event names used by WebAuthn flows.

type WebAuthnSessionRecord added in v0.4.0

type WebAuthnSessionRecord struct {
	UserID      string
	TenantID    string
	Purpose     byte
	SessionJSON []byte
}

WebAuthnSessionRecord is a flow-local pending-ceremony record.

Jump to

Keyboard shortcuts

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