emailtoken

package
v1.4.0 Latest Latest
Warning

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

Go to latest
Published: Nov 3, 2026 License: MIT Imports: 8 Imported by: 0

Documentation

Overview

Package emailtoken creates and checks the single-use tokens sent in emails: verification, password reset, and email change.

Like session tokens, only a token's SHA-256 hash is stored. A token works once, for one kind of action, until it expires. Creating a token cancels the user's earlier unused tokens of the same kind, and a user gets at most one new token of each kind per Cooldown, which limits how many emails anyone can trigger until real rate limiting exists.

Index

Constants

View Source
const Cooldown = 60 * time.Second

Cooldown is the minimum time between two tokens of the same kind for one user.

View Source
const MaxFailedAttempts = 5

MaxFailedAttempts is how many wrong passwords can be entered with a token before it stops working, so a stolen link can't be used to guess a password.

Variables

View Source
var (
	// ErrInvalid means a token is malformed, unknown, for a different kind
	// of action, used, expired, or locked by failed attempts. These cases
	// are deliberately indistinguishable to callers.
	ErrInvalid = errors.New("email token is invalid or expired")
	// ErrCooldown means the user was sent a token of this kind less than
	// Cooldown ago.
	ErrCooldown = errors.New("email token requested too soon")
)

Functions

This section is empty.

Types

type Conn

type Conn interface {
	db.DBTX
	Begin(ctx context.Context) (pgx.Tx, error)
}

Conn is a database connection that can start a transaction: a pool, or a transaction (which starts a savepoint).

type Kind

type Kind string

Kind is what a token is for.

const (
	VerifyEmail   Kind = "verify_email"
	ResetPassword Kind = "reset_password"
	ChangeEmail   Kind = "change_email"
)

Token kinds.

func (Kind) Lifetime

func (k Kind) Lifetime() time.Duration

Lifetime returns how long a token of kind k works.

type Manager

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

Manager manages email tokens in the database.

func NewManager

func NewManager(conn Conn, now func() time.Time) *Manager

NewManager returns a Manager using conn. now supplies the current time; pass time.Now outside tests.

func (*Manager) Create

func (m *Manager) Create(ctx context.Context, userID uuid.UUID, kind Kind, newEmail string) (string, Token, error)

Create makes a new token of kind for userID and returns it. The token is returned only here, to be put in an email. newEmail is required for ChangeEmail and must be empty otherwise. It returns ErrCooldown if the user got a token of this kind less than Cooldown ago.

func (*Manager) DeleteSpent

func (m *Manager) DeleteSpent(ctx context.Context) (int64, error)

DeleteSpent removes used and expired tokens and returns how many were removed. Run it periodically; spent tokens are already rejected, so this only frees space.

func (*Manager) Lookup

func (m *Manager) Lookup(ctx context.Context, tok string, kind Kind) (Token, error)

Lookup returns the token tok if it's usable for kind, without using it. Call Use to spend it.

func (*Manager) RecordFailure

func (m *Manager) RecordFailure(ctx context.Context, id uuid.UUID) error

RecordFailure counts a wrong password entered with token id. After MaxFailedAttempts the token stops working.

func (*Manager) Use

func (m *Manager) Use(ctx context.Context, id uuid.UUID) error

Use spends token id so it can't be used again. It returns ErrInvalid if the token stopped being usable since Lookup, e.g. because a concurrent request used it first. Call it in the same transaction as the action the token authorizes, so the token is spent only if the action happens.

type Token

type Token struct {
	ID     uuid.UUID
	UserID uuid.UUID
	Kind   Kind
	// NewEmail is the address being switched to, for ChangeEmail only.
	NewEmail  string
	ExpiresAt time.Time
}

Token is a stored email token. It never contains the token itself.

Jump to

Keyboard shortcuts

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