stores

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: 9 Imported by: 0

Documentation

Overview

Package stores provides Redis-backed, short-lived record stores for security-sensitive authentication flows: password reset, email verification, and MFA login challenges.

Design

Each store persists a versioned, binary-encoded record in Redis with a TTL. Mutation operations (Consume, RecordFailure) use WATCH/MULTI optimistic transactions with automatic retry on contention. Records are single-use: consumed or deleted on success, and enforce attempt limits to resist brute-force attacks. Secret comparisons use constant-time compare.

Architecture boundaries

This package owns persistence and concurrency control for transient challenge records. It does NOT generate tokens/OTPs, enforce rate limits, or make authentication decisions — those responsibilities belong to the flow functions in internal/flows.

What this package must NOT do

  • Import goAuth or any sibling internal package.
  • Log or expose plaintext secrets.
  • Use non-constant-time comparisons for secret matching.

Index

Constants

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

WebAuthn ceremony purposes. A session saved for one purpose must never be consumable for the other.

Variables

View Source
var (
	ErrVerificationNotFound         = errors.New("verification record not found")
	ErrVerificationSecretMismatch   = errors.New("verification secret mismatch")
	ErrVerificationAttemptsExceeded = errors.New("verification attempts exceeded")
	ErrVerificationRedisUnavailable = errors.New("verification redis unavailable")
)
View Source
var (
	ErrMFALoginChallengeNotFound = errors.New("mfa challenge not found")
	ErrMFALoginChallengeExpired  = errors.New("mfa challenge expired")
	ErrMFALoginChallengeExceeded = errors.New("mfa challenge attempts exceeded")
	ErrMFALoginChallengeBackend  = errors.New("mfa challenge backend unavailable")
)
View Source
var (
	ErrResetNotFound         = errors.New("reset record not found")
	ErrResetSecretMismatch   = errors.New("reset secret mismatch")
	ErrResetAttemptsExceeded = errors.New("reset attempts exceeded")
	ErrResetRedisUnavailable = errors.New("reset redis unavailable")
)
View Source
var (
	ErrWebAuthnSessionNotFound = errors.New("webauthn ceremony session not found")
	ErrWebAuthnSessionBackend  = errors.New("webauthn ceremony backend unavailable")
)

Functions

This section is empty.

Types

type EmailVerificationRecord

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

type EmailVerificationStore

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

func NewEmailVerificationStore

func NewEmailVerificationStore(redisClient redis.UniversalClient, prefix string) *EmailVerificationStore

func (*EmailVerificationStore) Consume

func (s *EmailVerificationStore) Consume(
	ctx context.Context,
	tenantID, verificationID string,
	providedHash [32]byte,
	expectedStrategy int,
	maxAttempts int,
) (*EmailVerificationRecord, error)

func (*EmailVerificationStore) Save

func (s *EmailVerificationStore) Save(
	ctx context.Context,
	tenantID, verificationID string,
	record *EmailVerificationRecord,
	ttl time.Duration,
) error

type MFALoginChallenge

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

type MFALoginChallengeStore

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

func NewMFALoginChallengeStore

func NewMFALoginChallengeStore(redisClient redis.UniversalClient, prefix string) *MFALoginChallengeStore

func (*MFALoginChallengeStore) Delete

func (s *MFALoginChallengeStore) Delete(ctx context.Context, challengeID string) (bool, error)

func (*MFALoginChallengeStore) Get

func (s *MFALoginChallengeStore) Get(ctx context.Context, challengeID string) (*MFALoginChallenge, error)

func (*MFALoginChallengeStore) RecordFailure

func (s *MFALoginChallengeStore) RecordFailure(
	ctx context.Context,
	challengeID string,
	maxAttempts int,
) (bool, error)

func (*MFALoginChallengeStore) Save

func (s *MFALoginChallengeStore) Save(
	ctx context.Context,
	challengeID string,
	record *MFALoginChallenge,
	ttl time.Duration,
) error

type PasswordResetRecord

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

type PasswordResetStore

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

func NewPasswordResetStore

func NewPasswordResetStore(redisClient redis.UniversalClient, prefix string) *PasswordResetStore

func (*PasswordResetStore) Consume

func (s *PasswordResetStore) Consume(
	ctx context.Context,
	tenantID, resetID string,
	providedHash [32]byte,
	expectedStrategy int,
	maxAttempts int,
) (*PasswordResetRecord, error)

func (*PasswordResetStore) Get

func (s *PasswordResetStore) Get(ctx context.Context, tenantID, resetID string) (*PasswordResetRecord, error)

func (*PasswordResetStore) Save

func (s *PasswordResetStore) Save(
	ctx context.Context,
	tenantID, resetID string,
	record *PasswordResetRecord,
	ttl time.Duration,
) error

type WebAuthnSession added in v0.4.0

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

WebAuthnSession is a pending WebAuthn ceremony: the library session data (challenge et al.) bound to the user and purpose it was begun for.

type WebAuthnSessionStore added in v0.4.0

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

WebAuthnSessionStore persists pending ceremony sessions in Redis with a TTL. Sessions are single-use: Consume atomically reads and deletes.

func NewWebAuthnSessionStore added in v0.4.0

func NewWebAuthnSessionStore(redisClient redis.UniversalClient, prefix string) *WebAuthnSessionStore

func (*WebAuthnSessionStore) Consume added in v0.4.0

func (s *WebAuthnSessionStore) Consume(ctx context.Context, ceremonyID string) (*WebAuthnSession, error)

Consume atomically fetches and deletes the ceremony session, enforcing single use: a replayed ceremony ID observes ErrWebAuthnSessionNotFound.

func (*WebAuthnSessionStore) Delete added in v0.4.0

func (s *WebAuthnSessionStore) Delete(ctx context.Context, ceremonyID string) error

Delete removes a pending ceremony session (best-effort cleanup).

func (*WebAuthnSessionStore) Save added in v0.4.0

func (s *WebAuthnSessionStore) Save(
	ctx context.Context,
	ceremonyID string,
	record *WebAuthnSession,
	ttl time.Duration,
) error

Jump to

Keyboard shortcuts

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