token

package
v0.0.10 Latest Latest
Warning

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

Go to latest
Published: Sep 18, 2026 License: Apache-2.0, MIT Imports: 12 Imported by: 0

Documentation

Overview

Package token owns the shared one-shot token store (public.auth_tokens): rows keyed by (user_id, purpose), SHA-256 hash at rest, single-use consumption with an expiry check. Consumers (emailverification, onetimeaccess) scope a store with their purpose and keep their own sentinels/TTLs.

Index

Constants

This section is empty.

Variables

View Source
var ErrNotFound = errors.New("token: invalid or expired")

ErrNotFound is returned by Consume for unknown, expired, or already-used tokens — indistinguishable by design. Consumers map it onto their own sentinel.

Functions

func Hash

func Hash(raw string) string

Hash derives the at-rest form of a raw token (SHA-256, base64url).

func NewRaw

func NewRaw() (string, error)

NewRaw draws a fresh opaque 256-bit token, base64url-encoded. Callers store token.Hash(raw) and deliver raw once.

Types

type PostgresStore

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

PostgresStore persists tokens in public.auth_tokens, scoped to one purpose per instance.

func NewStore

func NewStore(exec datastore.Executor, purpose Purpose) *PostgresStore

NewStore builds the production store for one purpose.

func (*PostgresStore) Consume

func (s *PostgresStore) Consume(ctx context.Context, tokenHash string) (*Token, error)

Consume deletes + returns the token for the hash; only an unexpired token resolves.

func (*PostgresStore) Upsert

func (s *PostgresStore) Upsert(ctx context.Context, token *Token) error

Upsert writes (or replaces) the single token per user+purpose and stamps last_sent_at.

type Purpose

type Purpose string

Purpose discriminates the auth_tokens rows; values are stored verbatim (DB CHECK constrains them).

const (
	// PurposeEmailVerification covers email verification links.
	PurposeEmailVerification Purpose = "email_verification"
	// PurposeOneTimeAccess covers one-time access sign-in tokens.
	PurposeOneTimeAccess Purpose = "one_time_access"
	// PurposeReauthentication exists in the DB CHECK but has no consumer yet.
	PurposeReauthentication Purpose = "reauthentication"
	// PurposePasswordReset covers forgot/reset password tokens.
	PurposePasswordReset Purpose = "password_reset"
)

type Store

type Store interface {
	// Upsert writes (or replaces) the single token per user+purpose.
	Upsert(ctx context.Context, token *Token) error
	// Consume deletes + returns the token for the hash; only an
	// unexpired token resolves.
	Consume(ctx context.Context, tokenHash string) (*Token, error)
}

Store persists purpose-scoped tokens.

type Token

type Token struct {
	ID        string
	UserID    string
	TokenHash string
	CreatedAt time.Time
	ExpiresAt time.Time
	// LastSentAt tracks the most recent delivery for resend
	// throttling; nil when never sent.
	LastSentAt *time.Time
}

Token is one auth_tokens row. UserID is the bare UUID column form.

Jump to

Keyboard shortcuts

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