Documentation
¶
Overview ¶
Package twofactor defines event names and typed event payloads published by the TwoFactor plugin on the global EventBus.
Package twofactor provides functional options, callbacks, and configuration settings for the TwoFactor plugin.
Index ¶
- Constants
- Variables
- func TwoFactorMethodKey(userID string) string
- func TwoFactorPendingKey(userID string) string
- func TwoFactorVerifiedKey(userID string) string
- type Config
- type DisableParams
- type DisableTwoFactorEventPayload
- type EnableParams
- type EnableResult
- type EnableTwoFactorAfterEventPayload
- type EnableTwoFactorBeforeEventPayload
- type GenerateBackupCodesParams
- type GetTOTPURIParams
- type OTPChallenge
- type Option
- func WithAllowPasswordless(allow bool) Option
- func WithBackupCodeOptions(amount, length int) Option
- func WithIssuer(issuer string) Option
- func WithLockoutProtection(maxAttempts int, duration time.Duration) Option
- func WithSendOTP(fn SendOTPFunc) Option
- func WithSkipVerificationOnEnable(skip bool) Option
- func WithTOTPOptions(digits int, period int) Option
- type Plugin
- func (p *Plugin) Disable(ctx context.Context, params DisableParams) error
- func (p *Plugin) Enable(ctx context.Context, params EnableParams) (*EnableResult, error)
- func (p *Plugin) GenerateBackupCodes(ctx context.Context, params GenerateBackupCodesParams) ([]string, error)
- func (p *Plugin) GenerateTOTPSecret(ctx context.Context, userID string) (string, error)
- func (p *Plugin) GetTOTPURI(ctx context.Context, params GetTOTPURIParams) (string, error)
- func (p *Plugin) ID() string
- func (p *Plugin) Init(ctx *plugin.Context) error
- func (p *Plugin) SendOTP(ctx context.Context, params SendOTPParams) error
- func (p *Plugin) VerifyBackupCode(ctx context.Context, params VerifyBackupCodeParams) (bool, error)
- func (p *Plugin) VerifyCode(ctx context.Context, userID, code string) (bool, error)
- func (p *Plugin) VerifyOTP(ctx context.Context, params VerifyOTPParams) (bool, error)
- func (p *Plugin) VerifyTOTP(ctx context.Context, params VerifyTOTPParams) (bool, error)
- func (p *Plugin) ViewBackupCodes(ctx context.Context, params ViewBackupCodesParams) ([]string, error)
- type Repository
- type SendOTPAfterEventPayload
- type SendOTPBeforeEventPayload
- type SendOTPFunc
- type SendOTPParams
- type TOTPGeneratedEventPayload
- type TwoFactor
- type VerifyBackupCodeAfterEventPayload
- type VerifyBackupCodeParams
- type VerifyOTPAfterEventPayload
- type VerifyOTPParams
- type VerifyTOTPAfterEventPayload
- type VerifyTOTPBeforeEventPayload
- type VerifyTOTPParams
- type ViewBackupCodesParams
Constants ¶
const ( // EventEnableTwoFactorBefore is emitted right before starting 2FA enrollment for a user. // Payload: *EnableTwoFactorBeforeEventPayload EventEnableTwoFactorBefore = "twofactor:enable:before" // EventEnableTwoFactorAfter is emitted after successfully generating and persisting 2FA secrets and backup codes. // Payload: *EnableTwoFactorAfterEventPayload EventEnableTwoFactorAfter = "twofactor:enable:after" // EventDisableTwoFactorBefore is emitted before disabling 2FA credentials for a user. // Payload: *DisableTwoFactorEventPayload EventDisableTwoFactorBefore = "twofactor:disable:before" // EventDisableTwoFactorAfter is emitted after 2FA credentials have been removed from storage. // Payload: *DisableTwoFactorEventPayload EventDisableTwoFactorAfter = "twofactor:disable:after" // EventVerifyTOTPBefore is emitted before validating a user-provided TOTP code. // Payload: *VerifyTOTPBeforeEventPayload EventVerifyTOTPBefore = "twofactor:verify_totp:before" // EventVerifyTOTPAfter is emitted after verifying a TOTP code, indicating success or failure. // Payload: *VerifyTOTPAfterEventPayload EventVerifyTOTPAfter = "twofactor:verify_totp:after" // EventSendOTPBefore is emitted before generating and sending an SMS/Email OTP challenge. // Payload: *SendOTPBeforeEventPayload EventSendOTPBefore = "twofactor:send_otp:before" // EventSendOTPAfter is emitted after an OTP challenge has been successfully dispatched. // Payload: *SendOTPAfterEventPayload EventSendOTPAfter = "twofactor:send_otp:after" // EventVerifyOTPAfter is emitted after validating an active OTP challenge. // Payload: *VerifyOTPAfterEventPayload EventVerifyOTPAfter = "twofactor:verify_otp:after" // EventVerifyBackupCodeAfter is emitted after verifying and consuming a single-use backup code. // Payload: *VerifyBackupCodeAfterEventPayload EventVerifyBackupCodeAfter = "twofactor:verify_backup_code:after" // EventTOTPGenerated is emitted whenever a raw Base32 TOTP secret is created. // Payload: *TOTPGeneratedEventPayload EventTOTPGenerated = "twofactor:totp:generated" )
const ( // ExtraKeyTwoFactorMethod specifies the method used for 2FA (e.g. "totp", "backup_code", "otp", "sms", "email"). ExtraKeyTwoFactorMethod = "two_factor_method" // ExtraKeyDeviceID represents the unique hardware or installation identifier of the client device. ExtraKeyDeviceID = "device_id" // ExtraKeyIPAddress represents the IP address of the client performing 2FA enrollment or verification. ExtraKeyIPAddress = "ip_address" // ExtraKeyUserAgent represents the User-Agent header of the client device during 2FA operations. ExtraKeyUserAgent = "user_agent" // ExtraKeySessionID represents the session ID associated with the 2FA authentication flow. ExtraKeySessionID = "session_id" // ExtraKeyIssuer overrides the default application issuer name shown in authenticator apps. ExtraKeyIssuer = "issuer" // ExtraKeyPhoneNumber represents the destination phone number for SMS OTP challenges. ExtraKeyPhoneNumber = "phone_number" // ExtraKeyEmail represents the destination email address for Email OTP challenges. ExtraKeyEmail = "email" // ExtraKeyTwoFactorVerified indicates if two-factor verification succeeded. ExtraKeyTwoFactorVerified = "two_factor_verified" )
Standard Extra metadata keys that can be set or consumed in TwoFactor parameters (such as EnableParams.Extra, DisableParams.Extra, and Event payloads).
const ( // MethodTOTP represents Time-based One-Time Password authentication (RFC 6238). MethodTOTP = "totp" // MethodBackupCode represents single-use recovery backup codes. MethodBackupCode = "backup_code" // MethodOTP represents challenge-based one-time password verification. MethodOTP = "otp" // MethodSMS represents SMS-delivered OTP challenges. MethodSMS = "sms" // MethodEmail represents Email-delivered OTP challenges. MethodEmail = "email" )
Supported two-factor authentication method constants.
const ( // ContextKeyTwoFactorPendingPrefix is the key prefix indicating a pending 2FA challenge for a user. ContextKeyTwoFactorPendingPrefix = "2fa_pending_" // ContextKeyTwoFactorVerifiedPrefix is the key prefix indicating verified 2FA status for a user. ContextKeyTwoFactorVerifiedPrefix = "2fa_verified_" // ContextKeyTwoFactorMethodPrefix is the key prefix indicating the active 2FA method for a user. ContextKeyTwoFactorMethodPrefix = "2fa_method_" )
Context keys stored in plugin.Context for TwoFactor state management.
const PluginID = "two-factor"
PluginID is the unique string identifier for the TwoFactor plugin ("two-factor").
Variables ¶
var ( // ErrTwoFactorNotEnabled is returned when 2FA operations are attempted for a user without active 2FA configuration. ErrTwoFactorNotEnabled = errors.New("twofactor: two-factor authentication is not enabled for this user") // ErrTwoFactorAlreadyOn is returned when attempting to enable 2FA on an account that already has verified 2FA active. ErrTwoFactorAlreadyOn = errors.New("twofactor: two-factor authentication is already enabled") // ErrInvalidCode is returned when a provided TOTP or backup code is invalid or does not match stored credentials. ErrInvalidCode = errors.New("twofactor: invalid verification code") // ErrAccountLocked is returned when 2FA verification is temporarily locked due to excessive failed attempts. ErrAccountLocked = errors.New("twofactor: two-factor authentication is temporarily locked due to excessive failed attempts") // ErrOTPNotConfigured is returned when attempting to send an OTP challenge without a registered SendOTP delivery callback. ErrOTPNotConfigured = errors.New("twofactor: send OTP callback is not configured") // ErrOTPExpired is returned when attempting to verify an OTP challenge that has expired or does not exist. ErrOTPExpired = errors.New("twofactor: OTP challenge has expired or does not exist") // ErrTooManyAttempts is returned when the maximum number of failed attempts on an active OTP challenge has been exceeded. ErrTooManyAttempts = errors.New("twofactor: maximum OTP attempt limit reached") // ErrPasswordRequired is returned when an operation strictly requires password confirmation before proceeding. ErrPasswordRequired = errors.New("twofactor: password is required for this operation") )
Functions ¶
func TwoFactorMethodKey ¶ added in v0.4.0
TwoFactorMethodKey formats the context store key used to track the active 2FA method for the given user.
func TwoFactorPendingKey ¶ added in v0.4.0
TwoFactorPendingKey formats the context store key used to track a pending 2FA verification for the given user.
func TwoFactorVerifiedKey ¶ added in v0.4.0
TwoFactorVerifiedKey formats the context store key used to track a completed 2FA verification for the given user.
Types ¶
type Config ¶
type Config struct {
// Issuer specifies the application name embedded into the TOTP URI shown in authenticator apps (default: "GoModularAuth").
Issuer string
// TotpDigits specifies the number of digits in generated TOTP codes (6 or 8, default: 6).
TotpDigits int
// TotpPeriod specifies the rotation interval for TOTP codes in seconds (default: 30).
TotpPeriod int
// BackupCodeAmount defines the total number of single-use backup codes generated during enrollment (default: 10).
BackupCodeAmount int
// BackupCodeLength defines the character length of each generated backup code (default: 10).
BackupCodeLength int
// AllowPasswordless allows 2FA management operations without requiring prior password re-validation.
AllowPasswordless bool
// SkipVerificationOnEnable marks 2FA as immediately active upon enrollment without demanding a first verified TOTP code.
SkipVerificationOnEnable bool
// MaxAllowedAttempts defines the maximum failed attempts permitted before rate limiting lockout triggers (default: 5).
MaxAllowedAttempts int
// LockoutDuration defines the temporary lockout penalty after exceeding maximum failed attempts (default: 15 minutes).
LockoutDuration time.Duration
// OTPDigits specifies the numeric length for challenge-based OTP codes (default: 6).
OTPDigits int
// OTPPeriod defines the expiration duration for temporary OTP challenges (default: 3 minutes).
OTPPeriod time.Duration
// SendOTP registers the external delivery callback for SMS or Email OTP dispatches.
SendOTP SendOTPFunc
}
Config holds configuration parameters for the two-factor authentication plugin.
func DefaultConfig ¶
func DefaultConfig() Config
DefaultConfig returns the default production configuration for the TwoFactor plugin.
type DisableParams ¶
type DisableParams struct {
// UserID identifies the user whose 2FA is being deactivated (required).
UserID string `json:"user_id"`
// Password is the optional password confirmation.
Password string `json:"password,omitempty"`
// Extra holds dynamic metadata passed through event interceptors (optional).
Extra map[string]any `json:"extra,omitempty"`
}
DisableParams defines parameters to disable 2FA for a user.
type DisableTwoFactorEventPayload ¶
type DisableTwoFactorEventPayload struct {
// UserID identifies the user whose 2FA configuration is being disabled.
UserID string
}
DisableTwoFactorEventPayload contains the user ID associated with a 2FA disablement event.
type EnableParams ¶
type EnableParams struct {
// UserID is the unique identifier of the user enrolling in 2FA (required).
UserID string `json:"user_id"`
// Password is the user's current password if password re-authentication is enforced (optional).
Password string `json:"password,omitempty"`
// Issuer overrides the default application issuer name shown in authenticator apps (optional).
Issuer string `json:"issuer,omitempty"`
// Extra holds dynamic metadata passed through event interceptors (optional).
Extra map[string]any `json:"extra,omitempty"`
}
EnableParams defines parameters required to initialize 2FA enrollment for a user.
func (*EnableParams) Get ¶
func (p *EnableParams) Get(key string) (any, bool)
Get retrieves a dynamic metadata value attached to the enrollment request.
func (*EnableParams) Set ¶
func (p *EnableParams) Set(key string, value any)
Set allows event interceptor plugins to attach dynamic metadata to the enrollment request.
type EnableResult ¶
type EnableResult struct {
// TOTPURI is the otpauth:// URI encoded with secret, issuer, digits, and period for QR code generation.
TOTPURI string `json:"totp_uri"`
// BackupCodes is the list of generated single-use recovery codes.
BackupCodes []string `json:"backup_codes"`
}
EnableResult contains the generated TOTP setup URI and initial single-use backup codes.
type EnableTwoFactorAfterEventPayload ¶
type EnableTwoFactorAfterEventPayload struct {
// UserID identifies the user whose 2FA enrollment completed.
UserID string
// BackupCodesCount is the number of single-use backup codes generated.
BackupCodesCount int
}
EnableTwoFactorAfterEventPayload contains confirmation details after 2FA secrets have been created.
type EnableTwoFactorBeforeEventPayload ¶
type EnableTwoFactorBeforeEventPayload struct {
// UserID identifies the user beginning 2FA setup.
UserID string
// Params holds the mutable enrollment parameters (including dynamic Extra metadata).
Params *EnableParams
}
EnableTwoFactorBeforeEventPayload contains the user ID and mutable parameters for pre-enrollment interception.
type GenerateBackupCodesParams ¶
type GenerateBackupCodesParams struct {
// UserID identifies the user requesting new backup codes (required).
UserID string `json:"user_id"`
// Password is an optional password check.
Password string `json:"password,omitempty"`
}
GenerateBackupCodesParams defines parameters to regenerate a fresh set of single-use backup codes.
type GetTOTPURIParams ¶
type GetTOTPURIParams struct {
// UserID identifies the enrolled user (required).
UserID string `json:"user_id"`
// Password is an optional password check.
Password string `json:"password,omitempty"`
}
GetTOTPURIParams defines parameters to retrieve the TOTP URI for an already configured user.
type OTPChallenge ¶
type OTPChallenge struct {
// Key is the unique challenge storage key (e.g. "2fa-otp-<userID>").
Key string `json:"key"`
// UserID is the recipient user's unique identifier.
UserID string `json:"user_id"`
// CodeHash is the generated numeric OTP challenge code.
CodeHash string `json:"code_hash"`
// Attempts tracks the number of failed verification tries against this specific challenge.
Attempts int `json:"attempts"`
// ExpiresAt specifies the exact timestamp after which this challenge is invalid.
ExpiresAt time.Time `json:"expires_at"`
}
OTPChallenge represents a temporary, short-lived one-time challenge delivered via SMS or Email.
type Option ¶
type Option func(*Config)
Option defines a functional option for configuring the TwoFactor plugin.
func WithAllowPasswordless ¶
WithAllowPasswordless allows 2FA operations without requiring prior user password verification.
func WithBackupCodeOptions ¶
WithBackupCodeOptions sets the quantity and character length of single-use backup codes generated during 2FA setup.
func WithIssuer ¶
WithIssuer sets the issuer name displayed in authenticator applications (e.g. "My Company ERP").
func WithLockoutProtection ¶
WithLockoutProtection configures the maximum allowed failed attempts before rate limiting locks the account, and the lockout penalty duration.
func WithSendOTP ¶
func WithSendOTP(fn SendOTPFunc) Option
WithSendOTP registers the delivery callback function used to dispatch temporary challenge OTP codes via SMS or Email.
func WithSkipVerificationOnEnable ¶
WithSkipVerificationOnEnable marks 2FA as actively enforced immediately upon secret generation.
type Plugin ¶
type Plugin struct {
// contains filtered or unexported fields
}
Plugin implements Two-Factor Authentication capabilities.
func New ¶
func New(repo Repository, opts ...Option) *Plugin
New creates a new TwoFactor plugin instance with the specified repository and functional options.
Arguments:
- repo: Implementation of twofactor.Repository interface.
- opts: Optional functional configuration options (WithIssuer, WithTOTPOptions, WithBackupCodeOptions, etc.).
Returns:
- *Plugin: The configured TwoFactor plugin instance.
func (*Plugin) Disable ¶
func (p *Plugin) Disable(ctx context.Context, params DisableParams) error
Disable removes 2FA configuration for the given user, effectively deactivating two-factor enforcement.
Brief Explanation:
Deletes the user's TwoFactor record from storage and emits EventDisableTwoFactorBefore and EventDisableTwoFactorAfter.
Function:
Deactivates MFA for a user account.
Arguments:
- ctx: Request cancellation context.
- params: DisableParams containing UserID and optional Password.
Returns:
- error: Nil on success, or database error on failure.
Example:
err := tfPlugin.Disable(ctx, twofactor.DisableParams{
UserID: "usr_12345",
})
if err != nil {
log.Fatalf("Disable 2FA failed: %v", err)
}
func (*Plugin) Enable ¶
func (p *Plugin) Enable(ctx context.Context, params EnableParams) (*EnableResult, error)
Enable enables 2FA enrollment for a user, generates a secure Base32 TOTP secret and backup codes, persists the TwoFactor record, and returns the TOTP URI alongside unconsumed recovery codes.
Brief Explanation:
Generates a cryptographically random 20-byte secret encoded in Base32, creates the configured amount of alphanumeric backup recovery codes, stores the TwoFactor entity in the repository, and publishes EventEnableTwoFactorBefore, EventEnableTwoFactorAfter, and EventTOTPGenerated.
Function:
Initial step for enrolling a user in Two-Factor Authentication.
Arguments:
- ctx: Request cancellation context.
- params: EnableParams containing UserID, optional Password, Issuer, and dynamic Extra metadata.
Returns:
- *EnableResult: Contains the otpauth:// URI for QR display and the slice of single-use backup codes.
- error: Database failure error if persistence fails.
Example:
res, err := tfPlugin.Enable(ctx, twofactor.EnableParams{
UserID: "usr_12345",
Issuer: "Enterprise Cloud",
})
if err != nil {
log.Fatalf("Enable 2FA failed: %v", err)
}
fmt.Printf("Scan QR Code URI: %s\n", res.TOTPURI)
fmt.Printf("Save your backup codes: %v\n", res.BackupCodes)
func (*Plugin) GenerateBackupCodes ¶
func (p *Plugin) GenerateBackupCodes(ctx context.Context, params GenerateBackupCodesParams) ([]string, error)
GenerateBackupCodes regenerates a fresh set of single-use recovery codes, overwriting any previous codes.
Brief Explanation:
Generates new alphanumeric codes according to BackupCodeAmount and BackupCodeLength, serializes them to JSON, and saves the updated TwoFactor record.
Function:
Allows users to regenerate recovery codes when running low or following a security reset.
Arguments:
- ctx: Request cancellation context.
- params: GenerateBackupCodesParams containing UserID and optional Password.
Returns:
- []string: The slice of freshly generated single-use backup codes.
- error: ErrTwoFactorNotEnabled or database error.
Example:
codes, err := tfPlugin.GenerateBackupCodes(ctx, twofactor.GenerateBackupCodesParams{
UserID: "usr_12345",
})
func (*Plugin) GenerateTOTPSecret ¶
GenerateTOTPSecret provides a convenience wrapper for simple TOTP secret generation, returning the setup URI.
func (*Plugin) GetTOTPURI ¶
GetTOTPURI retrieves the TOTP setup URI for an already configured user.
Brief Explanation:
Looks up the user's stored Base32 secret and reconstructs the otpauth:// URI for re-display in settings.
Function:
Retrieves QR code URI for existing 2FA users.
Arguments:
- ctx: Request cancellation context.
- params: GetTOTPURIParams containing UserID.
Returns:
- string: The full otpauth:// URI string.
- error: ErrTwoFactorNotEnabled if user has not enrolled in 2FA.
Example:
uri, err := tfPlugin.GetTOTPURI(ctx, twofactor.GetTOTPURIParams{
UserID: "usr_12345",
})
func (*Plugin) SendOTP ¶
func (p *Plugin) SendOTP(ctx context.Context, params SendOTPParams) error
SendOTP generates a short-lived numeric challenge and triggers the registered SendOTP delivery callback (SMS/Email).
Brief Explanation:
Generates a cryptographically secure random numeric string of length OTPDigits, persists an OTPChallenge record with an expiration timestamp, calls the user's SendOTP callback, and publishes EventSendOTPBefore and EventSendOTPAfter.
Function:
Out-of-band challenge-based 2FA (e.g. SMS code or Email verification).
Arguments:
- ctx: Request cancellation context.
- params: SendOTPParams containing UserID.
Returns:
- error: ErrOTPNotConfigured if no SendOTP callback was configured, or delivery error.
Example:
err := tfPlugin.SendOTP(ctx, twofactor.SendOTPParams{
UserID: "usr_12345",
})
func (*Plugin) VerifyBackupCode ¶
VerifyBackupCode verifies and atomically consumes a single-use backup code.
Brief Explanation:
Validates the user's recovery code (case-insensitive, ignoring hyphens), removes the used code from storage so it cannot be reused, resets failure counters, and emits EventVerifyBackupCodeAfter with the number of remaining backup codes.
Function:
Account recovery when an authenticator device is lost.
Arguments:
- ctx: Request cancellation context.
- params: VerifyBackupCodeParams containing UserID and Code.
Returns:
- bool: True if the backup code was valid and successfully consumed.
- error: ErrTwoFactorNotEnabled, ErrAccountLocked, ErrInvalidCode, or database error.
Example:
ok, err := tfPlugin.VerifyBackupCode(ctx, twofactor.VerifyBackupCodeParams{
UserID: "usr_12345",
Code: "AB87-C192",
})
if err != nil {
log.Fatalf("Backup code invalid: %v", err)
}
func (*Plugin) VerifyCode ¶
VerifyCode provides a convenience wrapper for simple TOTP code validation.
func (*Plugin) VerifyOTP ¶
VerifyOTP validates a user-submitted code against an active OTP challenge.
Brief Explanation:
Retrieves the stored challenge, checks expiration and maximum attempt thresholds, validates equality, deletes the challenge on success (enforcing single use), or increments attempt counters on failure. Emits EventVerifyOTPAfter.
Function:
Validates temporary challenge codes delivered out-of-band.
Arguments:
- ctx: Request cancellation context.
- params: VerifyOTPParams containing UserID and Code.
Returns:
- bool: True if verification succeeds.
- error: ErrOTPExpired, ErrTooManyAttempts, ErrInvalidCode, or database error.
Example:
ok, err := tfPlugin.VerifyOTP(ctx, twofactor.VerifyOTPParams{
UserID: "usr_12345",
Code: "938102",
})
func (*Plugin) VerifyTOTP ¶
VerifyTOTP validates a user-provided RFC 6238 TOTP code against their stored secret with a ±1 period drift window.
Brief Explanation:
Checks if the user account is locked due to rate limiting, calculates HMAC-SHA1 codes across the tolerance window (t-period, t, t+period), increments failure count on mismatch (locking account if limit reached), resets failures on success, marks 2FA as verified, and emits EventVerifyTOTPBefore and EventVerifyTOTPAfter.
Function:
Primary second-factor verification step during login or sensitive operations.
Arguments:
- ctx: Request cancellation context.
- params: VerifyTOTPParams containing UserID and the numeric Code string.
Returns:
- bool: True if the code matches.
- error: ErrTwoFactorNotEnabled, ErrAccountLocked, ErrInvalidCode, or database error.
Example:
ok, err := tfPlugin.VerifyTOTP(ctx, twofactor.VerifyTOTPParams{
UserID: "usr_12345",
Code: "482910",
})
if err != nil {
log.Fatalf("Verification rejected: %v", err)
}
fmt.Printf("2FA Verification Successful: %t\n", ok)
func (*Plugin) ViewBackupCodes ¶
func (p *Plugin) ViewBackupCodes(ctx context.Context, params ViewBackupCodesParams) ([]string, error)
ViewBackupCodes returns the list of active unconsumed single-use backup codes.
Brief Explanation:
Retrieves and parses the user's TwoFactor backup codes array from storage.
Function:
Allows authenticated users to view their remaining recovery codes in profile security settings.
Arguments:
- ctx: Request cancellation context.
- params: ViewBackupCodesParams containing UserID.
Returns:
- []string: The slice of remaining active backup codes.
- error: ErrTwoFactorNotEnabled or database error.
Example:
codes, err := tfPlugin.ViewBackupCodes(ctx, twofactor.ViewBackupCodesParams{
UserID: "usr_12345",
})
type Repository ¶
type Repository interface {
// FindByUserID retrieves the 2FA configuration record for a given user ID.
//
// Function:
// Used during TOTP validation, backup code verification, and viewing active backup codes.
//
// Arguments:
// - ctx: Request cancellation context.
// - userID: The unique user identifier to look up.
//
// Returns:
// - *TwoFactor: The populated TwoFactor configuration entity.
// - error: ErrTwoFactorNotEnabled if no record exists, or database error on failure.
//
// Example SQL:
// SELECT id, user_id, secret, backup_codes, verified, failures, locked_until, created_at, updated_at
// FROM two_factors WHERE user_id = $1 LIMIT 1;
FindByUserID(ctx context.Context, userID string) (*TwoFactor, error)
// Create persists a new TwoFactor entity in storage.
//
// Function:
// Called during Enable when initializing 2FA enrollment for a user.
//
// Arguments:
// - ctx: Request cancellation context.
// - tf: The newly initialized TwoFactor struct.
//
// Returns:
// - error: Nil on success, or database error on failure.
//
// Example SQL:
// INSERT INTO two_factors (id, user_id, secret, backup_codes, verified, failures, locked_until, created_at, updated_at)
// VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9);
Create(ctx context.Context, tf *TwoFactor) error
// Update modifies an existing TwoFactor record in storage.
//
// Function:
// Called after consuming a backup code, regenerating backup codes, updating failure counts,
// setting lockout expiration, or marking enrollment as verified.
//
// Arguments:
// - ctx: Request cancellation context.
// - tf: The modified TwoFactor struct.
//
// Returns:
// - error: Nil on success, or database error on failure.
//
// Example SQL:
// UPDATE two_factors SET secret = $1, backup_codes = $2, verified = $3, failures = $4, locked_until = $5, updated_at = $6
// WHERE user_id = $7;
Update(ctx context.Context, tf *TwoFactor) error
// DeleteByUserID removes 2FA configuration for a user ID when disabling 2FA.
//
// Function:
// Called during Disable to completely purge 2FA credentials for the user.
//
// Arguments:
// - ctx: Request cancellation context.
// - userID: The target user's ID.
//
// Returns:
// - error: Nil on success, or database error on failure.
//
// Example SQL:
// DELETE FROM two_factors WHERE user_id = $1;
DeleteByUserID(ctx context.Context, userID string) error
// SaveOTPChallenge stores or updates a short-lived challenge code.
//
// Function:
// Called during SendOTP when creating a new numeric challenge, or during VerifyOTP when incrementing failed attempts.
//
// Arguments:
// - ctx: Request cancellation context.
// - challenge: The OTPChallenge entity to persist or update.
//
// Returns:
// - error: Nil on success, or database error on failure.
//
// Example SQL / Redis:
// INSERT INTO otp_challenges (key, user_id, code_hash, attempts, expires_at)
// VALUES ($1, $2, $3, $4, $5) ON CONFLICT (key) DO UPDATE SET attempts = $4;
SaveOTPChallenge(ctx context.Context, challenge *OTPChallenge) error
// GetOTPChallenge retrieves an active challenge by its composite key.
//
// Function:
// Called during VerifyOTP to compare the user's submitted challenge code and verify expiration.
//
// Arguments:
// - ctx: Request cancellation context.
// - key: The composite challenge key (e.g. "2fa-otp-<userID>").
//
// Returns:
// - *OTPChallenge: The matching challenge entity.
// - error: ErrOTPExpired if no active challenge matches, or database error on failure.
//
// Example SQL:
// SELECT key, user_id, code_hash, attempts, expires_at FROM otp_challenges WHERE key = $1 LIMIT 1;
GetOTPChallenge(ctx context.Context, key string) (*OTPChallenge, error)
// DeleteOTPChallenge deletes a consumed or expired OTP challenge.
//
// Function:
// Called upon successful verification (single-use consumption) or when maximum attempts are exceeded.
//
// Arguments:
// - ctx: Request cancellation context.
// - key: The composite challenge key to delete.
//
// Returns:
// - error: Nil on success, or database error on failure.
//
// Example SQL:
// DELETE FROM otp_challenges WHERE key = $1;
DeleteOTPChallenge(ctx context.Context, key string) error
}
Repository defines the persistent storage contract required by the TwoFactor plugin. Implement this interface on your custom database adapter (e.g. PostgreSQL, MySQL, MongoDB, GORM).
Implementation Example (GORM / database/sql): ¶
type GormTwoFactorRepo struct {
db *gorm.DB
}
func (r *GormTwoFactorRepo) FindByUserID(ctx context.Context, userID string) (*twofactor.TwoFactor, error) {
var m TwoFactorModel
if err := r.db.WithContext(ctx).Where("user_id = ?", userID).First(&m).Error; err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, twofactor.ErrTwoFactorNotEnabled
}
return nil, err
}
return m.ToEntity(), nil
}
type SendOTPAfterEventPayload ¶
type SendOTPAfterEventPayload struct {
// UserID identifies the target user for the OTP challenge.
UserID string
// ExpiresAt specifies the exact expiration time for the OTP challenge.
ExpiresAt time.Time
}
SendOTPAfterEventPayload contains confirmation details after an OTP challenge has been dispatched.
type SendOTPBeforeEventPayload ¶
type SendOTPBeforeEventPayload struct {
// UserID identifies the target user for the OTP challenge.
UserID string
}
SendOTPBeforeEventPayload contains details before an OTP challenge is created.
type SendOTPFunc ¶
SendOTPFunc defines the callback function signature for dispatching generated OTP challenge codes via SMS or Email.
type SendOTPParams ¶
type SendOTPParams struct {
// UserID identifies the user receiving the OTP challenge (required).
UserID string `json:"user_id"`
}
SendOTPParams defines parameters to trigger an SMS or Email OTP challenge.
type TOTPGeneratedEventPayload ¶
type TOTPGeneratedEventPayload struct {
// UserID identifies the user for whom the secret was created.
UserID string
// Secret is the Base32-encoded TOTP secret.
Secret string
}
TOTPGeneratedEventPayload contains the raw secret generated during 2FA setup.
type TwoFactor ¶
type TwoFactor struct {
// ID is the unique database record identifier.
ID string `json:"id"`
// UserID uniquely identifies the owner user of this 2FA configuration.
UserID string `json:"user_id"`
// Secret is the Base32-encoded cryptographic secret used for TOTP calculation.
Secret string `json:"secret"`
// BackupCodes is a serialized JSON array containing unconsumed single-use backup codes (e.g. `["CODE1", "CODE2"]`).
BackupCodes string `json:"backup_codes"`
// Verified indicates whether initial TOTP verification has succeeded and 2FA is actively enforced.
Verified bool `json:"verified"`
// Failures tracks the number of consecutive failed verification attempts.
Failures int `json:"failures"`
// LockedUntil specifies the timestamp until which 2FA operations are locked due to rate limiting (nil if unlocked).
LockedUntil *time.Time `json:"locked_until"`
// CreatedAt records the timestamp when 2FA enrollment was initialized.
CreatedAt time.Time `json:"created_at"`
// UpdatedAt records the timestamp when 2FA settings were last modified.
UpdatedAt time.Time `json:"updated_at"`
}
TwoFactor represents the persistent storage entity containing a user's 2FA configuration, secrets, and security state.
type VerifyBackupCodeAfterEventPayload ¶
type VerifyBackupCodeAfterEventPayload struct {
// UserID identifies the user consuming a backup code.
UserID string
// Success indicates whether the backup code was found, valid, and consumed.
Success bool
// RemainingCodes is the count of remaining unconsumed backup codes.
RemainingCodes int
}
VerifyBackupCodeAfterEventPayload reports the result of a single-use backup code consumption attempt.
type VerifyBackupCodeParams ¶
type VerifyBackupCodeParams struct {
// UserID identifies the user attempting backup code recovery (required).
UserID string `json:"user_id"`
// Code is the alphanumeric single-use recovery code (required).
Code string `json:"code"`
}
VerifyBackupCodeParams defines parameters to verify and consume a single-use backup code.
type VerifyOTPAfterEventPayload ¶
type VerifyOTPAfterEventPayload struct {
// UserID identifies the user attempting OTP challenge verification.
UserID string
// Success indicates whether the challenge code was valid.
Success bool
}
VerifyOTPAfterEventPayload reports the result of an OTP challenge verification attempt.
type VerifyOTPParams ¶
type VerifyOTPParams struct {
// UserID identifies the user submitting the challenge verification code (required).
UserID string `json:"user_id"`
// Code is the numeric challenge code delivered to the user (required).
Code string `json:"code"`
}
VerifyOTPParams defines parameters to verify an active OTP challenge.
type VerifyTOTPAfterEventPayload ¶
type VerifyTOTPAfterEventPayload struct {
// UserID identifies the user who attempted TOTP validation.
UserID string
// Success indicates whether the submitted code was valid and accepted.
Success bool
}
VerifyTOTPAfterEventPayload reports the result of a TOTP code validation attempt.
type VerifyTOTPBeforeEventPayload ¶
type VerifyTOTPBeforeEventPayload struct {
// UserID identifies the user submitting the TOTP code.
UserID string
}
VerifyTOTPBeforeEventPayload contains details before a TOTP code is evaluated.
type VerifyTOTPParams ¶
type VerifyTOTPParams struct {
// UserID identifies the user submitting the verification code (required).
UserID string `json:"user_id"`
// Code is the numeric TOTP code generated by an authenticator application (required).
Code string `json:"code"`
}
VerifyTOTPParams defines parameters to verify an incoming 6- or 8-digit TOTP code.
type ViewBackupCodesParams ¶
type ViewBackupCodesParams struct {
// UserID identifies the user querying their backup codes (required).
UserID string `json:"user_id"`
}
ViewBackupCodesParams defines parameters to retrieve active unconsumed backup codes.