mfa

package module
v0.1.0 Latest Latest
Warning

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

Go to latest
Published: Jun 25, 2026 License: MIT Imports: 21 Imported by: 0

README

togo

togo-framework/auth-mfa

marketplace pkg.go.dev MIT

Multi-factor auth & account protection for the togo auth family.

Install

togo install togo-framework/auth-mfa

Adds the security layer Fort-grade auth needs, on top of the togo auth plugin: TOTP 2FA + recovery codes, email OTP, magic-link login, account lockout, password policy, and an MFA challenge state-machine that gates a full session behind a second factor.

The challenge flow

primary login ──► if mfa.Required(user): IssueChallenge() ──► challenge token (5 min, NOT a session)
                                                                    │
        client completes a factor (TOTP / recovery / OTP) ─────────┘
                                                                    ▼
                          on success: auth.IssueSession()  ──►  real session

Challenge tokens are HMAC-signed with purpose=mfa and are rejected as sessions.

Endpoints (/api/auth/mfa)

Method Path Purpose
POST /totp/enroll generate a TOTP secret + otpauth:// URI (QR)
POST /totp/verify verify a code (activates; pass challenge to complete login)
POST /totp/disable remove 2FA
POST /recovery/generate 8 single-use recovery codes (shown once)
POST /recovery/verify consume a recovery code
POST /otp/send email a 6-digit OTP (rate-limited 3/10min)
POST /otp/verify verify the OTP
POST /magic-link/send email a signed login link
GET /magic-link/verify?token= log in via the link
GET /challenge/status?challenge= inspect a pending challenge

Go API

m, _ := mfa.FromKernel(k)

if m.Required(userID) {
    tok, _ := m.IssueChallenge(userID)   // hand the client a challenge token instead of a session
}

secret, uri, _ := m.EnrollTOTP(userID, "MyApp")   // show the QR
m.VerifyTOTP(userID, "123456")                    // activates on first success
codes := m.GenerateRecoveryCodes(userID, 8)

m.RecordFailure(userID); locked, until := m.IsLocked(userID)   // lockout
m.ValidatePassword(pw)                                          // policy

Configuration

Env Default
MFA_CHALLENGE_SECRET dev secret HMAC key for challenge / magic-link tokens — set in prod
MFA_OTP_TTL 5m email-OTP lifetime
MFA_LOCKOUT_THRESHOLD 5 failures before lock
MFA_LOCKOUT_MINUTES 15 lock duration
MFA_PW_MIN_LEN 12 password minimum length

OTP/magic-link delivery: wire the togo mail/notifications plugin (the code is logged in dev). State is in a bounded in-memory store with a pluggable Store (WithStore) for DB persistence.


Premium sponsors

ID8 Media  ·  One Studio

Support togo — become a sponsor.

Documentation

Overview

Package mfa adds multi-factor auth + account protection to the togo auth family: a challenge state-machine (login → challenge token → factor → session), TOTP 2FA with recovery codes, email OTP, magic-link login, account lockout, and password policy.

m, _ := mfa.FromKernel(k)
if m.Required(userID) { // issue a challenge instead of a session
    tok, _ := m.IssueChallenge(userID)
}

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Config

type Config struct {
	ChallengeSecret  []byte
	ChallengeTTL     time.Duration
	OTPTTL           time.Duration
	OTPRatePer10Min  int
	LockoutThreshold int
	LockoutMinutes   int
	PwMinLen         int
}

Config is read from env on boot.

type Lockout

type Lockout struct {
	Failures    int
	LastFailure time.Time
	LockedUntil time.Time
}

Lockout tracks failed-login state for a user.

type OTPCode

type OTPCode struct {
	UserID  string
	Code    string
	Expires time.Time
}

OTPCode is a time-limited email OTP.

type RecoveryCode

type RecoveryCode struct {
	UserID string
	Hash   string
	Used   bool
}

RecoveryCode is a single-use backup code (stored hashed).

type Service

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

Service is the MFA runtime stored on the kernel (k.Get("mfa")).

func FromKernel

func FromKernel(k *togo.Kernel) (*Service, bool)

FromKernel returns the MFA Service.

func (*Service) Cfg

func (s *Service) Cfg() Config

Config returns the active configuration.

func (*Service) DisableTOTP

func (s *Service) DisableTOTP(userID string)

DisableTOTP removes a user's TOTP enrollment.

func (*Service) EnrollTOTP

func (s *Service) EnrollTOTP(userID, issuer string) (secret, uri string, err error)

EnrollTOTP generates a new (inactive) TOTP secret for a user and returns the otpauth:// provisioning URI (render it as a QR code client-side).

func (*Service) GenerateRecoveryCodes

func (s *Service) GenerateRecoveryCodes(userID string, n int) []string

GenerateRecoveryCodes creates n single-use codes, stores their hashes, and returns the plaintext codes (shown to the user ONCE).

func (*Service) IsLocked

func (s *Service) IsLocked(userID string) (bool, time.Time)

IsLocked reports whether a user is currently locked, and until when.

func (*Service) IssueChallenge

func (s *Service) IssueChallenge(userID string) (string, error)

IssueChallenge mints a short-lived signed challenge token (NOT a session).

func (*Service) MagicLinkToken

func (s *Service) MagicLinkToken(userID string) string

MagicLinkToken mints a signed login token for a user (reuses the challenge signing with a distinct purpose).

func (*Service) RecordFailure

func (s *Service) RecordFailure(userID string)

RecordFailure increments a user's failure counter; locks after the threshold.

func (*Service) Required

func (s *Service) Required(userID string) bool

Required reports whether the user has any active factor (TOTP enrolled).

func (*Service) Reset

func (s *Service) Reset(userID string)

Reset clears a user's failure/lock state (call on a successful login).

func (*Service) SendOTP

func (s *Service) SendOTP(userID string) (string, error)

SendOTP generates a 6-digit code for the user (rate-limited). The caller is responsible for delivery (email/SMS); the code is returned for the caller to send (and logged in dev). Returns the code + an error if rate-limited.

func (*Service) ValidatePassword

func (s *Service) ValidatePassword(pw string) error

ValidatePassword checks a password against the configured policy.

func (*Service) ValidateTOTPAt

func (s *Service) ValidateTOTPAt(secret, code string, at time.Time) (bool, error)

ValidateTOTPAt verifies a code at a specific time (used by tests).

func (*Service) VerifyChallenge

func (s *Service) VerifyChallenge(token string) (string, error)

VerifyChallenge validates a challenge token and returns its user id.

func (s *Service) VerifyMagicLink(token string) (string, error)

VerifyMagicLink validates a magic-link token, returning the user id.

func (*Service) VerifyOTP

func (s *Service) VerifyOTP(userID, code string) bool

VerifyOTP checks an email OTP (single-use, expiring).

func (*Service) VerifyRecoveryCode

func (s *Service) VerifyRecoveryCode(userID, code string) bool

VerifyRecoveryCode consumes a single-use recovery code.

func (*Service) VerifyTOTP

func (s *Service) VerifyTOTP(userID, code string) bool

VerifyTOTP checks a code; on the first valid code it activates the secret.

func (*Service) WithStore

func (s *Service) WithStore(store Store) *Service

WithStore swaps the backing store (e.g. a DB-backed one).

type Store

type Store interface {
	SetTOTP(TOTPSecret)
	GetTOTP(userID string) (TOTPSecret, bool)
	DeleteTOTP(userID string)

	AddRecoveryCodes(userID string, hashes []string)
	ConsumeRecovery(userID, hash string) bool // returns true if a matching unused code was consumed

	SetOTP(OTPCode)
	GetOTP(userID string) (OTPCode, bool)
	DeleteOTP(userID string)
	OTPSendsSince(userID string, since time.Time) int
	RecordOTPSend(userID string, at time.Time)

	GetLockout(userID string) Lockout
	SetLockout(userID string, l Lockout)
}

Store is the MFA persistence seam (swap the in-memory default for a DB one).

type TOTPSecret

type TOTPSecret struct {
	UserID    string
	Secret    string // base32
	Activated bool
	CreatedAt time.Time
}

TOTPSecret is a user's enrolled authenticator secret.

Jump to

Keyboard shortcuts

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