mfa

package
v0.2.0 Latest Latest
Warning

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

Go to latest
Published: Sep 25, 2026 License: MIT Imports: 10 Imported by: 0

Documentation

Overview

Package mfa defines the multi-factor authentication method drivers, the enrollment Store and the registry that resolves configured methods per request.

Index

Constants

View Source
const (
	InteractionCode = "code" // submit a code / assertion via POST /mfa/verify
	InteractionPoll = "poll" // wait for out-of-band approval via GET /mfa/status
)

Interaction hints surfaced to the client for the selected method.

Variables

View Source
var (
	// ErrUnknownMethod is returned when no configured or registered method matches the name.
	ErrUnknownMethod = errors.New("unknown mfa method")
	// ErrNotEnrolled is returned when the user has no matching enrollment.
	ErrNotEnrolled = errors.New("mfa method not enrolled")
	// ErrInvalidResponse is returned by Method.FinishEnroll for a wrong code or malformed
	// response, counting as a failed attempt.
	ErrInvalidResponse = errors.New("invalid mfa response")
)

Functions

func EnrolledMethods

func EnrolledMethods(ctx context.Context, s Store, userID string) ([]string, error)

EnrolledMethods returns the names of the methods userID is enrolled in, in enrollment order.

func MethodAMR

func MethodAMR(m Method) []string

MethodAMR returns the amr values m records when it passes.

func MethodBackup

func MethodBackup(m Method) bool

MethodBackup reports whether m only backs up another factor.

func MethodExclusive

func MethodExclusive(m Method) bool

MethodExclusive reports whether m holds at most one enrollment per user.

func MethodInteraction

func MethodInteraction(m Method) string

MethodInteraction returns the client interaction hint for m.

func Register

func Register(name string, d Driver)

Register makes a Driver available under name.

Panics on a nil or duplicate registration.

Types

type AMRProvider

type AMRProvider interface {
	AMR() []string
}

AMRProvider is an optional Method extension declaring the RFC 8176 amr values recorded when the factor passes. Without it "mfa" alone is recorded.

type AsyncMethod

type AsyncMethod interface {
	Async() bool
}

AsyncMethod is an optional Method extension for factors verified out-of-band (push approval): the login flow signals InteractionPoll instead of prompting for a code.

type BackupMethod

type BackupMethod interface {
	Backup() bool
}

BackupMethod is an optional Method extension for factors that only back up another one (ex. recovery codes).

type CallbackHandler

type CallbackHandler interface {
	HandleCallback(ctx *azugo.Context) error
}

CallbackHandler is an optional Method extension for vendors that deliver approval via an inbound webhook, dispatched from POST /mfa/callback/{method}. That route is unauthenticated and not rate limited.

type Driver

type Driver interface {
	// Open creates a Method over the shared store from the configuration entry.
	Open(store Store, cfg *contract.MFAMethodConfig) (Method, error)
}

Driver is implemented by each MFA method package and registered via Register.

type Enrollment

type Enrollment struct {
	ID     string
	UserID string
	Method string
	// Label is the user-facing name of the device or app.
	Label string
	// Secret is the driver-specific enrollment data; never surfaced to clients.
	Secret     []byte
	CreatedAt  time.Time
	LastUsedAt *time.Time
}

Enrollment is one enrolled instance of a method for a user: an authenticator app, a device or a code set. A user may hold several per method.

func Enrolled

func Enrolled(ctx context.Context, s Store, userID, method string) ([]*Enrollment, error)

Enrolled returns userID's enrollments in method, oldest first.

type EnrollmentData

type EnrollmentData struct {
	// Data is surfaced to the client, e.g. {"secret":"...","uri":"otpauth://..."} for TOTP.
	Data map[string]any
	// State is opaque driver state the library hands back to FinishEnroll; never surfaced.
	State []byte
}

EnrollmentData is returned by BeginEnroll.

type ExclusiveMethod

type ExclusiveMethod interface {
	Exclusive() bool
}

ExclusiveMethod is an optional Method extension for factors holding at most one enrollment per user.

type Method

type Method interface {
	// BeginEnroll returns enrollment data for the user.
	BeginEnroll(ctx context.Context, userID string, info contract.UserInfo) (EnrollmentData, error)
	// FinishEnroll verifies the enrollment response against state and returns the secret the
	// library stores; a wrong response returns ErrInvalidResponse.
	FinishEnroll(ctx context.Context, userID string, state []byte, response map[string]any) ([]byte, error)
	// BeginVerify starts a challenge across the user's enrollments. challengeID is the opaque
	// server-side handle; data is surfaced to the client. Both are empty for self-contained
	// methods (TOTP).
	BeginVerify(ctx context.Context, userID string) (challengeID string, data map[string]any, err error)
	// Verify evaluates response against challengeID and the user's enrollments. response is nil
	// when polling an async method.
	Verify(ctx context.Context, userID, challengeID string, response map[string]any) (Verification, error)
}

Method encapsulates one authentication factor.

type Registry

type Registry interface {
	// Get returns the method available under name, or ErrUnknownMethod.
	Get(ctx context.Context, name string) (Method, error)
	// Names returns every available method name, configured entries first.
	Names(ctx context.Context) ([]string, error)
}

Registry resolves MFA methods by name.

func NewConfigRegistry

func NewConfigRegistry(config *contract.Configuration, store Store) Registry

NewConfigRegistry creates the default Registry.

type Store

type Store interface {
	// List returns userID's enrollments, oldest first.
	List(ctx context.Context, userID string) ([]*Enrollment, error)
	// Enroll persists e under its ID, replacing an enrollment with the same ID.
	Enroll(ctx context.Context, e *Enrollment) error
	// CompareAndSwap replaces the secret of userID's enrollment id only when its current value
	// equals expected. It returns false when the enrollment is missing or has changed, allowing
	// one-time factors to be consumed exactly once across concurrent requests.
	CompareAndSwap(ctx context.Context, userID, id string, expected, replacement []byte) (bool, error)
	// Touch records that userID's enrollment id passed verification at at, or ErrNotEnrolled.
	Touch(ctx context.Context, userID, id string, at time.Time) error
	// Revoke removes userID's enrollment id, or ErrNotEnrolled.
	Revoke(ctx context.Context, userID, id string) error
}

Store persists MFA enrollments.

func NewMemoryStore

func NewMemoryStore() Store

NewMemoryStore creates an empty in-memory Store.

Warning: Use it only for development and/or testing.

type Verification

type Verification struct {
	Result VerifyResult
	// EnrollmentID names the enrollment that satisfied the factor, when the method knows it.
	EnrollmentID string
}

Verification is the outcome of Method.Verify.

type VerifyResult

type VerifyResult string

VerifyResult is the tri-state outcome of Method.Verify.

const (
	VerifyApproved VerifyResult = "approved" // factor satisfied - advance the session
	VerifyDenied   VerifyResult = "denied"   // wrong code / rejected push - a failed attempt
	VerifyPending  VerifyResult = "pending"  // async method awaiting out-of-band approval
)

VerifyResult values.

Directories

Path Synopsis
Package recovery is the backup/recovery-code MFA driver: single-use codes that unlock an account when the primary factor is lost.
Package recovery is the backup/recovery-code MFA driver: single-use codes that unlock an account when the primary factor is lost.
Package totp is the built-in RFC 6238 time-based one-time password MFA driver.
Package totp is the built-in RFC 6238 time-based one-time password MFA driver.

Jump to

Keyboard shortcuts

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