user

package
v0.3.0 Latest Latest
Warning

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

Go to latest
Published: Aug 26, 2026 License: MIT Imports: 8 Imported by: 0

Documentation

Overview

Package user implements user registration, authentication, session management, password reset, email verification, and TOTP-based two-factor auth. It depends only on the store interfaces it needs (no concrete database) and on a jwt.Signer for token issuance.

Index

Constants

This section is empty.

Variables

View Source
var (
	ErrInvalidCredentials  = errors.New("authit/user: invalid credentials")
	ErrEmailTaken          = errors.New("authit/user: email already registered")
	ErrEmailNotVerified    = errors.New("authit/user: email not verified")
	ErrAccountLocked       = errors.New("authit/user: account locked")
	ErrInvalidToken        = errors.New("authit/user: invalid or expired token")
	ErrTwoFactorRequired   = errors.New("authit/user: two-factor code required")
	ErrTwoFactorEnabled    = errors.New("authit/user: two-factor already enabled")
	ErrTwoFactorNotEnabled = errors.New("authit/user: two-factor not enabled")
	ErrInvalidTwoFactor    = errors.New("authit/user: invalid two-factor code")
	ErrSessionNotFound     = errors.New("authit/user: session not found")
)

Functions

This section is empty.

Types

type AuthResult

type AuthResult struct {
	User                  store.User
	Tokens                *TokenPair
	RequiresTwoFactor     bool
	PendingTwoFactorToken string
}

AuthResult is the outcome of Authenticate. Exactly one of Tokens or PendingTwoFactorToken is set: if the account has 2FA enabled, the caller must call VerifyTwoFactorLogin with PendingTwoFactorToken to obtain Tokens.

type Config

type Config struct {
	// AccessTokenTTL is how long an issued access JWT is valid for.
	AccessTokenTTL time.Duration
	// RefreshTokenTTL is how long a refresh token (session) stays valid if
	// never revoked.
	RefreshTokenTTL time.Duration
	// PasswordResetTTL is how long a password reset link stays valid.
	PasswordResetTTL time.Duration
	// EmailVerificationTTL is how long an email verification link stays
	// valid.
	EmailVerificationTTL time.Duration
	// PendingTwoFactorTTL is how long a caller has to complete the 2FA step
	// after a correct password before having to log in again.
	PendingTwoFactorTTL time.Duration
	// MaxFailedLoginAttempts is how many recent failed logins lock the
	// account.
	MaxFailedLoginAttempts int
	// FailedLoginWindow is the lookback window used when counting recent
	// failed attempts.
	FailedLoginWindow time.Duration
	// TOTPIssuer is the issuer name embedded in generated TOTP QR codes.
	TOTPIssuer string
	// TOTPEncryptionKey encrypts TOTP secrets at rest (AES-256-GCM). Must be
	// exactly 32 bytes. Required if 2FA methods are used.
	TOTPEncryptionKey []byte
	// BackupCodeCount is how many backup codes are generated on 2FA setup.
	BackupCodeCount int
	// EmailVerification decides whether Authenticate gates login on
	// User.EmailVerified. Defaults to EmailVerificationRequired.
	EmailVerification EmailVerificationPolicy
	// AuditLogger receives security-relevant events (login, lockout,
	// password/2FA changes, session revocation). Nil means events are not
	// recorded — see package audit.
	AuditLogger audit.Logger
}

Config tunes the user package's flows. Zero-value fields are replaced with sane defaults by NewService.

type EmailSender

type EmailSender interface {
	SendPasswordReset(ctx context.Context, email, token string) error
	SendEmailVerification(ctx context.Context, email, token string) error
}

EmailSender delivers the links/codes authit's flows generate. authit ships no concrete implementation; host applications wire in whatever sends mail (SMTP, a queue, a transactional-email API, ...).

type EmailVerificationPolicy

type EmailVerificationPolicy int

EmailVerificationPolicy decides whether Authenticate refuses a login from an account whose email address has not been verified yet.

The zero value is EmailVerificationRequired, so a Config that says nothing about this gets the strict behaviour.

const (
	// EmailVerificationRequired refuses to authenticate a user whose
	// address is not verified, returning ErrEmailNotVerified. This is the
	// default, and the right choice for a self-serve signup where the
	// address is otherwise unproven.
	EmailVerificationRequired EmailVerificationPolicy = iota
	// EmailVerificationOptional lets an unverified address log in. It is
	// for hosts whose signup path already proves the address by other
	// means — an emailed, tokenised B2B invite; SSO/IdP provisioning that
	// arrives pre-verified — and for seeded demo/test accounts. Verified
	// state is still tracked on the user, so the host can still gate its
	// own features on User.EmailVerified; only login stops depending on
	// it.
	EmailVerificationOptional
)

type NoopEmailSender

type NoopEmailSender struct{}

NoopEmailSender discards every message. Useful for tests, or apps that deliver verification/reset links out of band.

func (NoopEmailSender) SendEmailVerification

func (NoopEmailSender) SendEmailVerification(ctx context.Context, email, token string) error

func (NoopEmailSender) SendPasswordReset

func (NoopEmailSender) SendPasswordReset(ctx context.Context, email, token string) error

type Service

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

Service implements user auth flows.

func NewService

func NewService(stores Stores, signer authitjwt.Signer, emailer EmailSender, cfg Config) (*Service, error)

NewService constructs a Service. emailer may be nil, in which case NoopEmailSender is used (useful for tests or apps that deliver links out of band). Config.AuditLogger may be nil, in which case audit.NoopLogger is used.

func (*Service) Authenticate

func (s *Service) Authenticate(ctx context.Context, email, password, userAgent, ipAddress string) (AuthResult, error)

Authenticate verifies email/password and, if the account has no 2FA enabled, issues a token pair. If 2FA is enabled, it returns a pending two-factor token instead — call VerifyTwoFactorLogin to complete login.

Under the default Config.EmailVerification (EmailVerificationRequired) an account whose address is unverified is refused with ErrEmailNotVerified; see EmailVerificationPolicy for when to relax that.

func (*Service) BeginTwoFactorSetup

func (s *Service) BeginTwoFactorSetup(ctx context.Context, userID, accountEmail string) (TwoFactorSetup, error)

BeginTwoFactorSetup generates a new TOTP secret for userID and stores it (encrypted) with Enabled=false. The caller must call ConfirmTwoFactorSetup with a valid code before 2FA takes effect.

func (*Service) ChangePassword

func (s *Service) ChangePassword(ctx context.Context, userID, currentPassword, newPassword string) error

ChangePassword updates an authenticated user's password after verifying their current one.

func (*Service) ConfirmTwoFactorSetup

func (s *Service) ConfirmTwoFactorSetup(ctx context.Context, userID, code string) (TwoFactorEnrollment, error)

ConfirmTwoFactorSetup verifies a code against the pending secret from BeginTwoFactorSetup, enables 2FA, and returns freshly generated backup codes (plaintext, shown once).

func (*Service) DisableTwoFactor

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

DisableTwoFactor turns off 2FA, accepting either a TOTP code or a backup code (so a user who lost their authenticator can still disable it).

func (*Service) ListSessions

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

ListSessions returns every active (unrevoked, unexpired) session for a user. If currentRefreshToken is non-empty, the matching session (if any) is flagged IsCurrent.

func (*Service) Logout

func (s *Service) Logout(ctx context.Context, refreshToken string) error

Logout revokes a single refresh token. It is idempotent: revoking an already-revoked or unknown token is not an error.

func (*Service) MarkEmailVerified

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

MarkEmailVerified marks userID's address verified directly, without minting and redeeming a token. It is the trusted-caller counterpart to VerifyEmail, for the paths where the address is already proven and a round-trip through an email would be ceremony: a seeder provisioning demo or test accounts, a tokenised B2B invite the recipient just followed, or SSO/IdP provisioning that arrives pre-verified.

Never call this from an unauthenticated, user-supplied path — it is exactly the check VerifyEmail exists to perform.

It is idempotent: on an already-verified user it is a no-op and leaves EmailVerifiedAt at the original time. Any outstanding verification tokens for the user are deleted, so a link already in an inbox can't be redeemed afterwards.

func (*Service) Refresh

func (s *Service) Refresh(ctx context.Context, refreshToken, userAgent, ipAddress string) (TokenPair, error)

Refresh exchanges a valid, unrevoked refresh token for a new token pair, rotating the refresh token (the old one is revoked).

func (*Service) RegenerateBackupCodes

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

RegenerateBackupCodes invalidates existing backup codes and issues a new set. Requires a valid TOTP code (not a backup code, to stop a stolen backup code from being used to mint fresh ones).

func (*Service) Register

func (s *Service) Register(ctx context.Context, email, password string) (store.User, error)

Register creates a new user with the given email/password. The password is hashed before storage; the plaintext never leaves this call.

func (*Service) RequestEmailVerification

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

RequestEmailVerification generates a verification token for userID and emails it.

func (*Service) RequestEmailVerificationByEmail

func (s *Service) RequestEmailVerificationByEmail(ctx context.Context, email string) error

RequestEmailVerificationByEmail is the public, unauthenticated variant used for a "resend verification email" form. Like RequestPasswordReset, it always succeeds regardless of whether the address is registered or already verified, to avoid leaking account existence.

func (*Service) RequestPasswordReset

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

RequestPasswordReset generates a reset token and emails it to the given address. It always succeeds regardless of whether the address is registered, so callers can return the same response either way and avoid leaking account existence.

func (*Service) ResetPassword

func (s *Service) ResetPassword(ctx context.Context, rawToken, newPassword string) error

ResetPassword consumes a password reset token and sets a new password. Every other session for the user is revoked, forcing re-login everywhere else.

func (*Service) RevokeOtherSessions

func (s *Service) RevokeOtherSessions(ctx context.Context, userID, currentRefreshToken string) error

RevokeOtherSessions revokes every session for userID except the one matching currentRefreshToken.

func (*Service) RevokeSession

func (s *Service) RevokeSession(ctx context.Context, userID, sessionID string) error

RevokeSession revokes one session by ID, scoped to userID so a caller can't revoke another user's session.

func (*Service) TwoFactorStatus

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

TwoFactorStatus reports whether 2FA is enabled and how many backup codes remain.

func (*Service) ValidatePasswordResetToken

func (s *Service) ValidatePasswordResetToken(ctx context.Context, rawToken string) error

ValidatePasswordResetToken reports whether a reset token is still valid, without consuming it — used to give the UI an early error before the user types a new password.

func (*Service) VerifyEmail

func (s *Service) VerifyEmail(ctx context.Context, rawToken string) error

VerifyEmail consumes a verification token and marks the user's email verified.

func (*Service) VerifyTwoFactorLogin

func (s *Service) VerifyTwoFactorLogin(ctx context.Context, pendingToken, code, userAgent, ipAddress string) (AuthResult, error)

VerifyTwoFactorLogin completes a login that Authenticate flagged as RequiresTwoFactor: it exchanges the pending token plus a valid TOTP or backup code for a real token pair.

type Session

type Session struct {
	ID        string
	IsCurrent bool
	UserAgent string
	IPAddress string
	CreatedAt time.Time
	ExpiresAt time.Time
}

Session is a user-facing view of a RefreshToken, for session-management UIs (list active sessions, revoke one).

type Stores

type Stores struct {
	Users              store.UserStore
	RefreshTokens      store.RefreshTokenStore
	PasswordResets     store.PasswordResetStore
	EmailVerifications store.EmailVerificationStore
	TOTP               store.TOTPStore
	PendingTwoFactor   store.PendingTwoFactorStore
	Lockouts           store.LockoutStore
}

Stores groups the persistence ports the user package needs. A host application supplies concrete implementations (or reuses memstore).

type TokenPair

type TokenPair struct {
	AccessToken  string
	RefreshToken string
	ExpiresAt    time.Time
}

TokenPair is what a completed login/refresh returns to the caller.

type TwoFactorEnrollment

type TwoFactorEnrollment struct {
	BackupCodes []string
}

TwoFactorEnrollment is returned by ConfirmTwoFactorSetup: the plaintext backup codes, shown to the user exactly once.

type TwoFactorSetup

type TwoFactorSetup struct {
	Secret     string
	OTPAuthURL string
}

TwoFactorSetup is returned by BeginTwoFactorSetup; the caller renders Secret/OTPAuthURL as a QR code for the user to scan.

type TwoFactorStatus

type TwoFactorStatus struct {
	Enabled              bool
	VerifiedAt           *time.Time
	RemainingBackupCodes int
}

TwoFactorStatus reports a user's current 2FA state.

Jump to

Keyboard shortcuts

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