auth

package
v0.7.2 Latest Latest
Warning

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

Go to latest
Published: Mar 21, 2026 License: EUPL-1.2 Imports: 37 Imported by: 0

Documentation

Overview

Package auth provides authentication as a burrow contrib app.

It implements WebAuthn (passkeys), recovery codes, email verification, and invite-only registration. Context helpers provide access to the authenticated user from any handler.

Index

Examples

Constants

View Source
const (
	RoleUser  = "user"
	RoleAdmin = "admin"
)

Role constants.

View Source
const (
	// TokenLength is the number of random bytes for verification tokens.
	TokenLength = 32
	// TokenExpiry is how long verification tokens are valid.
	TokenExpiry = 24 * time.Hour
	// InviteExpiry is how long an invite token is valid.
	InviteExpiry = 7 * 24 * time.Hour
)
View Source
const (
	// CodeLength is the length of each recovery code (without dashes).
	CodeLength = 12
	// CodeCount is the default number of recovery codes to generate.
	CodeCount = 8
)

Variables

View Source
var ErrInviteAlreadyUsed = errors.New("invite already used")

ErrInviteAlreadyUsed is returned when an invite has already been consumed.

View Source
var ErrNotFound = sql.ErrNoRows

ErrNotFound is returned when a record is not found.

Functions

func DefaultAuthLayout

func DefaultAuthLayout() string

DefaultAuthLayout returns the template name for the built-in auth layout. Uses the base bootstrap layout directly.

func DefaultEmailRenderer

func DefaultEmailRenderer() authmail.Renderer

DefaultEmailRenderer returns a Renderer that uses the built-in HTML email templates with i18n support. When a localizer is present in the context (via i18n middleware or i18n.App.WithLocale), all strings are translated. Without a localizer, translation keys are returned as-is.

func GenerateInviteToken

func GenerateInviteToken() (plaintext, hash string, err error)

GenerateInviteToken generates a random invite token and its SHA256 hash.

func GenerateToken

func GenerateToken() (string, string, time.Time, error)

GenerateToken generates a new verification token. Returns (plaintext token, SHA256 hash for storage, expiry time, error).

func HashToken

func HashToken(token string) string

HashToken computes the SHA256 hash of a token.

func IsAuthenticated

func IsAuthenticated(ctx context.Context) bool

IsAuthenticated returns true if a user is present in the context.

Example
package main

import (
	"context"
	"fmt"

	"github.com/oliverandrich/burrow/contrib/auth"
)

func main() {
	// No user in context — not authenticated.
	fmt.Println(auth.IsAuthenticated(context.Background()))

	// With a user in context — authenticated.
	ctx := auth.WithUser(context.Background(), &auth.User{Username: "bob"})
	fmt.Println(auth.IsAuthenticated(ctx))
}
Output:

false
true
func Logo(ctx context.Context) template.HTML

Logo retrieves the logo HTML from context, or empty if not set.

func LogoFromContext

func LogoFromContext(ctx context.Context) template.HTML

LogoFromContext is a deprecated alias for Logo.

func NormalizeCode

func NormalizeCode(code string) string

NormalizeCode removes dashes and converts to lowercase for comparison.

Example
package main

import (
	"fmt"

	"github.com/oliverandrich/burrow/contrib/auth"
)

func main() {
	fmt.Println(auth.NormalizeCode("ABCD-EFGH-2345"))
}
Output:

abcdefgh2345

func RequireAdmin

func RequireAdmin() func(http.Handler) http.Handler

RequireAdmin returns middleware that enforces admin access. Unauthenticated users are redirected to login (like RequireAuth). Authenticated non-admin users see a 403 error page.

func RequireAuth

func RequireAuth() func(http.Handler) http.Handler

RequireAuth returns middleware that redirects to login if not authenticated. The original request URL is stored in the session as "redirect_after_login" so the user can be redirected back after successful authentication.

For GET requests, the full request URI is stored. For other methods (POST, PUT, DELETE, etc.), the Referer header is used instead — since the redirect back is always a GET, storing a POST-only URL would cause a 405.

func SafeRedirectPath

func SafeRedirectPath(next, defaultPath string) string

SafeRedirectPath validates a redirect path, falling back to defaultPath.

Example
package main

import (
	"fmt"

	"github.com/oliverandrich/burrow/contrib/auth"
)

func main() {
	// A relative path is accepted as-is.
	fmt.Println(auth.SafeRedirectPath("/profile", "/"))

	// An absolute URL with a host is rejected.
	fmt.Println(auth.SafeRedirectPath("https://evil.example.com", "/"))

	// An empty string falls back to the default.
	fmt.Println(auth.SafeRedirectPath("", "/home"))
}
Output:

/profile
/
/home

func TransportsFromWebAuthn

func TransportsFromWebAuthn(transports []protocol.AuthenticatorTransport) string

TransportsFromWebAuthn converts WebAuthn transports to a comma-separated string.

func WithLogo(ctx context.Context, logo template.HTML) context.Context

WithLogo returns a new context with the logo HTML set.

func WithUser

func WithUser(ctx context.Context, user *User) context.Context

WithUser returns a new context with the user set.

Types

type App

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

App implements the auth contrib app.

func New

func New(opts ...Option) *App

New creates a new auth app with the given options. By default, the built-in HTML renderer and auth layout are used. Use WithRenderer() and WithAuthLayout() to override.

func (*App) AdminNavItems

func (a *App) AdminNavItems() []burrow.NavItem

AdminNavItems returns navigation items for the admin panel.

func (*App) AdminRoutes

func (a *App) AdminRoutes(r chi.Router)

AdminRoutes registers admin routes for user and invite management. The router is expected to already have auth middleware applied.

func (*App) CLICommands

func (a *App) CLICommands() []*cli.Command

CLICommands returns auth-related CLI subcommands (promote, demote, create-invite).

func (*App) Configure

func (a *App) Configure(cmd *cli.Command) error

func (*App) Dependencies

func (a *App) Dependencies() []string

func (*App) Flags

func (a *App) Flags(configSource func(key string) cli.ValueSource) []cli.Flag

func (*App) FuncMap

func (a *App) FuncMap() template.FuncMap

FuncMap returns static template functions for auth templates.

func (*App) Handlers

func (a *App) Handlers() *Handlers

Handlers returns the auth handlers for external access.

func (*App) Middleware

func (a *App) Middleware() []func(http.Handler) http.Handler

func (*App) MigrationFS

func (a *App) MigrationFS() fs.FS

func (*App) Name

func (a *App) Name() string

func (*App) Register

func (a *App) Register(cfg *burrow.AppConfig) error

func (*App) RegisterJobs

func (a *App) RegisterJobs(q burrow.Queue)

RegisterJobs registers auth email job handlers with the queue.

func (*App) Repo

func (a *App) Repo() *Repository

Repo returns the auth repository for external access.

func (*App) RequestFuncMap

func (a *App) RequestFuncMap(r *http.Request) template.FuncMap

RequestFuncMap returns request-scoped template functions for auth state.

func (*App) Routes

func (a *App) Routes(r chi.Router)

Routes registers auth HTTP routes.

func (*App) Shutdown

func (a *App) Shutdown(_ context.Context) error

Shutdown stops the background cleanup goroutine. Safe to call multiple times or if Configure was never called.

func (*App) StaticFS

func (a *App) StaticFS() (string, fs.FS)

StaticFS returns the embedded static assets (webauthn.js) under the "auth" prefix.

func (*App) TemplateFS

func (a *App) TemplateFS() fs.FS

TemplateFS returns the embedded HTML template files.

func (*App) TranslationFS

func (a *App) TranslationFS() fs.FS

TranslationFS returns the embedded translation files for auto-discovery by the i18n app.

type Config

type Config struct {
	LoginRedirect       string
	LogoutRedirect      string
	BaseURL             string
	UseEmail            bool
	RequireVerification bool
	InviteOnly          bool
}

Config holds auth-specific configuration.

type CreateInviteRequest

type CreateInviteRequest struct {
	Label string `form:"label"`
	Email string `form:"email"`
}

CreateInviteRequest is the request body for creating an invite.

type Credential

type Credential struct {
	bun.BaseModel   `bun:"table:credentials,alias:c"`
	CreatedAt       time.Time `bun:",nullzero,notnull,default:current_timestamp" json:"created_at"`
	AttestationType string    `json:"-"`
	Transports      string    `json:"-"`
	Name            string    `bun:",notnull" json:"name"`
	CredentialID    []byte    `bun:",unique,notnull" json:"-"`
	PublicKey       []byte    `bun:",notnull" json:"-"`
	AAGUID          []byte    `json:"-"`
	ID              int64     `bun:",pk,autoincrement" json:"id"`
	UserID          int64     `bun:",notnull" json:"user_id"`
	SignCount       uint32    `bun:",default:0" json:"-"`
	BackupState     bool      `bun:",default:false" json:"-"`
	BackupEligible  bool      `bun:",default:false" json:"-"`
}

Credential stores a WebAuthn credential for a user.

func NewCredentialFromWebAuthn

func NewCredentialFromWebAuthn(userID int64, cred *webauthn.Credential) *Credential

NewCredentialFromWebAuthn creates a Credential from a WebAuthn registration result.

func (*Credential) ToWebAuthn

func (c *Credential) ToWebAuthn() webauthn.Credential

ToWebAuthn converts the stored credential to the WebAuthn library type.

type EmailService

type EmailService interface {
	SendVerification(ctx context.Context, toEmail, verifyURL string) error
	SendInvite(ctx context.Context, toEmail, inviteURL string) error
}

EmailService defines email operations.

type EmailVerificationToken

type EmailVerificationToken struct {
	bun.BaseModel `bun:"table:email_verification_tokens,alias:evt"`
	ExpiresAt     time.Time `bun:",notnull" json:"expires_at"`
	CreatedAt     time.Time `bun:",nullzero,notnull,default:current_timestamp" json:"created_at"`
	TokenHash     string    `bun:",unique,notnull" json:"-"`
	ID            int64     `bun:",pk,autoincrement" json:"id"`
	UserID        int64     `bun:",notnull" json:"user_id"`
}

EmailVerificationToken stores a hashed token for email verification.

type Handlers

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

Handlers contains all auth and invite HTTP handlers.

func NewHandlers

func NewHandlers(
	repo *Repository,
	wa WebAuthnService,
	email EmailService,
	renderer Renderer,
	config *Config,
	app *App,
) *Handlers

NewHandlers creates a new Handlers instance. email can be nil if email mode is disabled.

func (*Handlers) AcknowledgeRecoveryCodes

func (h *Handlers) AcknowledgeRecoveryCodes(w http.ResponseWriter, r *http.Request) error

AcknowledgeRecoveryCodes clears recovery codes from the session and redirects.

func (*Handlers) AddCredentialBegin

func (h *Handlers) AddCredentialBegin(w http.ResponseWriter, r *http.Request) error

AddCredentialBegin starts the process of adding a new credential.

func (*Handlers) AddCredentialFinish

func (h *Handlers) AddCredentialFinish(w http.ResponseWriter, r *http.Request) error

AddCredentialFinish completes adding a new credential.

func (*Handlers) CredentialsPage

func (h *Handlers) CredentialsPage(w http.ResponseWriter, r *http.Request) error

CredentialsPage renders the credentials management page.

func (*Handlers) DeleteCredential

func (h *Handlers) DeleteCredential(w http.ResponseWriter, r *http.Request) error

DeleteCredential removes a credential.

func (*Handlers) IsInviteOnly

func (h *Handlers) IsInviteOnly() bool

IsInviteOnly returns true if invite-only registration is enabled.

func (*Handlers) LoginBegin

func (h *Handlers) LoginBegin(w http.ResponseWriter, r *http.Request) error

LoginBegin starts the WebAuthn discoverable login process.

func (*Handlers) LoginFinish

func (h *Handlers) LoginFinish(w http.ResponseWriter, r *http.Request) error

LoginFinish completes the WebAuthn discoverable login.

func (*Handlers) LoginPage

func (h *Handlers) LoginPage(w http.ResponseWriter, r *http.Request) error

LoginPage renders the login page.

func (*Handlers) Logout

func (h *Handlers) Logout(w http.ResponseWriter, r *http.Request) error

Logout clears the session cookie.

func (*Handlers) RecoveryCodesPage

func (h *Handlers) RecoveryCodesPage(w http.ResponseWriter, r *http.Request) error

RecoveryCodesPage renders the dedicated recovery codes page. Codes are read from the session; if none are present, redirects to login redirect.

func (*Handlers) RecoveryLogin

func (h *Handlers) RecoveryLogin(w http.ResponseWriter, r *http.Request) error

RecoveryLogin authenticates a user with a recovery code.

func (*Handlers) RecoveryPage

func (h *Handlers) RecoveryPage(w http.ResponseWriter, r *http.Request) error

RecoveryPage renders the recovery login page.

func (*Handlers) RegenerateRecoveryCodes

func (h *Handlers) RegenerateRecoveryCodes(w http.ResponseWriter, r *http.Request) error

RegenerateRecoveryCodes generates new recovery codes and invalidates old ones. Stores codes in session and returns a redirect to the recovery codes page.

func (*Handlers) RegisterBegin

func (h *Handlers) RegisterBegin(w http.ResponseWriter, r *http.Request) error

RegisterBegin starts the WebAuthn registration process.

func (*Handlers) RegisterFinish

func (h *Handlers) RegisterFinish(w http.ResponseWriter, r *http.Request) error

RegisterFinish completes the WebAuthn registration process.

func (*Handlers) RegisterPage

func (h *Handlers) RegisterPage(w http.ResponseWriter, r *http.Request) error

RegisterPage renders the registration page.

func (*Handlers) ResendVerification

func (h *Handlers) ResendVerification(w http.ResponseWriter, r *http.Request) error

ResendVerification resends the verification email.

func (*Handlers) UseEmailMode

func (h *Handlers) UseEmailMode() bool

UseEmailMode returns true if email-based authentication is enabled.

func (*Handlers) VerifyEmail

func (h *Handlers) VerifyEmail(w http.ResponseWriter, r *http.Request) error

VerifyEmail handles the email verification link.

func (*Handlers) VerifyPendingPage

func (h *Handlers) VerifyPendingPage(w http.ResponseWriter, r *http.Request) error

VerifyPendingPage renders the "check your email" page.

type Invite

type Invite struct {
	bun.BaseModel `bun:"table:invites,alias:inv"`
	ExpiresAt     time.Time  `bun:",notnull" json:"expires_at" form:"-" verbose:"Expires at"`
	CreatedAt     time.Time  `bun:",nullzero,notnull,default:current_timestamp" json:"created_at" form:"-" verbose:"Created at"`
	UsedAt        *time.Time `json:"used_at,omitempty" form:"-"`
	UsedBy        *int64     `json:"used_by,omitempty" form:"-"`
	CreatedBy     *int64     `json:"created_by,omitempty" form:"-"`
	Email         string     `bun:",notnull" json:"email" verbose:"Email"`
	Label         string     `bun:",notnull,default:''" json:"label" verbose:"Label"`
	TokenHash     string     `bun:",unique,notnull" json:"-" form:"-"`
	ID            int64      `bun:",pk,autoincrement" json:"id" verbose:"ID"`
}

Invite represents an invitation to register.

func (*Invite) IsExpired

func (i *Invite) IsExpired() bool

IsExpired returns true if the invite has expired.

func (*Invite) IsUsed

func (i *Invite) IsUsed() bool

IsUsed returns true if the invite has been used.

func (*Invite) IsValid

func (i *Invite) IsValid() bool

IsValid returns true if the invite is neither used nor expired.

type Option

type Option func(*App)

Option configures the auth app.

func WithAuthLayout

func WithAuthLayout(name string) Option

WithAuthLayout sets an optional layout template name for public (unauthenticated) auth pages. When set, pages like login, register, and recovery use this layout instead of the global app layout. Authenticated routes (credentials, recovery codes) continue to use the global layout.

func WithEmailService

func WithEmailService(e EmailService) Option

WithEmailService sets the email service for the auth app.

func WithLogoComponent

func WithLogoComponent(c template.HTML) Option

WithLogoComponent sets an optional logo HTML rendered above auth page content. When set, the logo appears on login, register, and recovery pages.

func WithRenderer

func WithRenderer(r Renderer) Option

WithRenderer sets the page renderer for auth views.

type RecoveryCode

type RecoveryCode struct {
	bun.BaseModel `bun:"table:recovery_codes,alias:rc"`
	CreatedAt     time.Time  `bun:",nullzero,notnull,default:current_timestamp" json:"created_at"`
	UsedAt        *time.Time `json:"used_at,omitempty"`
	CodeHash      string     `bun:",notnull" json:"-"`
	ID            int64      `bun:",pk,autoincrement" json:"id"`
	UserID        int64      `bun:",notnull" json:"user_id"`
	Used          bool       `bun:",notnull,default:false" json:"used"`
}

RecoveryCode stores a hashed recovery code for account recovery.

type RecoveryLoginRequest

type RecoveryLoginRequest struct {
	Username string `json:"username" form:"username"`
	Code     string `json:"code" form:"code"`
}

RecoveryLoginRequest is the request body for recovery login.

type RecoveryService

type RecoveryService struct {
	// BcryptCost overrides the default bcrypt cost. Use bcrypt.MinCost in tests.
	BcryptCost int
}

RecoveryService handles recovery code generation.

func NewRecoveryService

func NewRecoveryService() *RecoveryService

NewRecoveryService creates a new recovery service.

func (*RecoveryService) GenerateCodes

func (s *RecoveryService) GenerateCodes(count int) ([]string, []string, error)

GenerateCodes generates recovery codes and their bcrypt hashes. Returns (plaintext codes for display, hashed codes for storage, error).

type RegisterBeginRequest

type RegisterBeginRequest struct {
	Username string `json:"username"`
	Email    string `json:"email"`
	Name     string `json:"name"`
	Invite   string `json:"invite"`
}

RegisterBeginRequest is the request body for starting registration.

type Renderer

type Renderer interface {
	RegisterPage(w http.ResponseWriter, r *http.Request, useEmail, inviteOnly bool, email, invite string) error
	LoginPage(w http.ResponseWriter, r *http.Request, loginRedirect string) error
	CredentialsPage(w http.ResponseWriter, r *http.Request, creds []Credential) error
	RecoveryPage(w http.ResponseWriter, r *http.Request, loginRedirect string) error
	RecoveryCodesPage(w http.ResponseWriter, r *http.Request, codes []string) error
	VerifyPendingPage(w http.ResponseWriter, r *http.Request) error
	VerifyEmailSuccessPage(w http.ResponseWriter, r *http.Request) error
	VerifyEmailErrorPage(w http.ResponseWriter, r *http.Request, errorCode string) error
}

Renderer defines the page rendering interface for auth templates. Projects implement this to provide their own template rendering.

func DefaultRenderer

func DefaultRenderer() Renderer

DefaultRenderer returns the default Renderer that uses the built-in HTML templates. Templates use burrow.RenderTemplate which reads layout from context: if a layout is set, page content is wrapped in it; otherwise bare content is rendered.

type Repository

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

Repository provides data access for auth models.

func NewRepository

func NewRepository(db *bun.DB) *Repository

NewRepository creates a new auth Repository.

func (*Repository) CountAdminUsers

func (r *Repository) CountAdminUsers(ctx context.Context) (int, error)

CountAdminUsers returns the number of users with the admin role.

func (*Repository) CountUserCredentials

func (r *Repository) CountUserCredentials(ctx context.Context, userID int64) (int64, error)

CountUserCredentials counts the number of credentials for a user.

func (*Repository) CountUsers

func (r *Repository) CountUsers(ctx context.Context) (int, error)

CountUsers returns the total number of users.

func (*Repository) CreateCredential

func (r *Repository) CreateCredential(ctx context.Context, cred *Credential) error

CreateCredential creates a new WebAuthn credential.

func (*Repository) CreateEmailVerificationToken

func (r *Repository) CreateEmailVerificationToken(ctx context.Context, userID int64, tokenHash string, expiresAt time.Time) error

CreateEmailVerificationToken creates a new email verification token.

func (*Repository) CreateInvite

func (r *Repository) CreateInvite(ctx context.Context, invite *Invite) error

CreateInvite creates a new invite record.

func (*Repository) CreateRecoveryCodes

func (r *Repository) CreateRecoveryCodes(ctx context.Context, userID int64, codeHashes []string) error

CreateRecoveryCodes creates recovery codes for a user.

func (*Repository) CreateUser

func (r *Repository) CreateUser(ctx context.Context, username, name string) (*User, error)

CreateUser creates a new user with a username and optional name.

func (*Repository) CreateUserWithEmail

func (r *Repository) CreateUserWithEmail(ctx context.Context, email, name string) (*User, error)

CreateUserWithEmail creates a new user with email and optional name.

func (*Repository) DeleteCredential

func (r *Repository) DeleteCredential(ctx context.Context, credID, userID int64) error

DeleteCredential deletes a credential.

func (*Repository) DeleteEmailVerificationToken

func (r *Repository) DeleteEmailVerificationToken(ctx context.Context, tokenID int64) error

DeleteEmailVerificationToken deletes a token.

func (*Repository) DeleteExpiredEmailVerificationTokens

func (r *Repository) DeleteExpiredEmailVerificationTokens(ctx context.Context) error

DeleteExpiredEmailVerificationTokens deletes expired tokens.

func (*Repository) DeleteInvite

func (r *Repository) DeleteInvite(ctx context.Context, inviteID int64) error

DeleteInvite deletes an invite (revoke).

func (*Repository) DeleteRecoveryCodes

func (r *Repository) DeleteRecoveryCodes(ctx context.Context, userID int64) error

DeleteRecoveryCodes deletes all recovery codes for a user.

func (*Repository) DeleteUser

func (r *Repository) DeleteUser(ctx context.Context, id int64) error

DeleteUser permanently deletes a user by ID.

func (*Repository) DeleteUserEmailVerificationTokens

func (r *Repository) DeleteUserEmailVerificationTokens(ctx context.Context, userID int64) error

DeleteUserEmailVerificationTokens deletes all tokens for a user.

func (*Repository) EmailExists

func (r *Repository) EmailExists(ctx context.Context, email string) (bool, error)

EmailExists checks if a user with the given email exists.

func (*Repository) GetCredentialsByUserID

func (r *Repository) GetCredentialsByUserID(ctx context.Context, userID int64) ([]Credential, error)

GetCredentialsByUserID retrieves all credentials for a user.

func (*Repository) GetEmailVerificationToken

func (r *Repository) GetEmailVerificationToken(ctx context.Context, tokenHash string) (*EmailVerificationToken, error)

GetEmailVerificationToken retrieves a token by hash.

func (*Repository) GetInviteByTokenHash

func (r *Repository) GetInviteByTokenHash(ctx context.Context, tokenHash string) (*Invite, error)

GetInviteByTokenHash retrieves an invite by its token hash.

func (*Repository) GetUnusedRecoveryCodeCount

func (r *Repository) GetUnusedRecoveryCodeCount(ctx context.Context, userID int64) (int64, error)

GetUnusedRecoveryCodeCount returns the count of unused recovery codes.

func (*Repository) GetUnusedRecoveryCodes

func (r *Repository) GetUnusedRecoveryCodes(ctx context.Context, userID int64) ([]RecoveryCode, error)

GetUnusedRecoveryCodes retrieves unused recovery codes for a user.

func (*Repository) GetUserByEmail

func (r *Repository) GetUserByEmail(ctx context.Context, email string) (*User, error)

GetUserByEmail retrieves a user by email.

func (*Repository) GetUserByID

func (r *Repository) GetUserByID(ctx context.Context, id int64) (*User, error)

GetUserByID retrieves a user by ID.

func (*Repository) GetUserByIDWithCredentials

func (r *Repository) GetUserByIDWithCredentials(ctx context.Context, id int64) (*User, error)

GetUserByIDWithCredentials retrieves a user by ID with preloaded credentials.

func (*Repository) GetUserByUsername

func (r *Repository) GetUserByUsername(ctx context.Context, username string) (*User, error)

GetUserByUsername retrieves a user by username.

func (*Repository) HasRecoveryCodes

func (r *Repository) HasRecoveryCodes(ctx context.Context, userID int64) (bool, error)

HasRecoveryCodes checks if a user has any recovery codes.

func (*Repository) ListInvites

func (r *Repository) ListInvites(ctx context.Context) ([]Invite, error)

ListInvites returns all invites ordered by creation date descending.

func (*Repository) ListUsers

func (r *Repository) ListUsers(ctx context.Context) ([]User, error)

ListUsers returns all users ordered by ID ascending.

func (*Repository) MarkEmailVerified

func (r *Repository) MarkEmailVerified(ctx context.Context, userID int64) error

MarkEmailVerified marks a user's email as verified.

func (*Repository) MarkInviteUsed

func (r *Repository) MarkInviteUsed(ctx context.Context, inviteID, userID int64) error

MarkInviteUsed atomically marks an invite as used by the given user. The WHERE used_at IS NULL clause ensures only the first caller succeeds, preventing a race condition where two registrations consume the same invite.

func (*Repository) MarkRecoveryCodeUsed

func (r *Repository) MarkRecoveryCodeUsed(ctx context.Context, codeID int64) error

MarkRecoveryCodeUsed marks a recovery code as used.

func (*Repository) PurgeOrphanedUsers

func (r *Repository) PurgeOrphanedUsers(ctx context.Context, olderThan time.Duration) (int, error)

PurgeOrphanedUsers deletes users with zero credentials that were created more than the given duration ago. These are leftover from abandoned WebAuthn registration flows where the client never called RegisterFinish.

func (*Repository) SetUserActive

func (r *Repository) SetUserActive(ctx context.Context, userID int64, active bool) error

SetUserActive sets a user's is_active flag.

func (*Repository) SetUserRole

func (r *Repository) SetUserRole(ctx context.Context, userID int64, role string) error

SetUserRole updates a user's role.

func (*Repository) UpdateCredentialSignCount

func (r *Repository) UpdateCredentialSignCount(ctx context.Context, credentialID []byte, signCount uint32) error

UpdateCredentialSignCount updates the sign count for a credential.

func (*Repository) UpdateUser

func (r *Repository) UpdateUser(ctx context.Context, user *User) error

UpdateUser updates a user record.

func (*Repository) UserExists

func (r *Repository) UserExists(ctx context.Context, username string) (bool, error)

UserExists checks if a user with the given username exists.

func (*Repository) ValidateAndUseRecoveryCode

func (r *Repository) ValidateAndUseRecoveryCode(ctx context.Context, userID int64, code string) (bool, error)

ValidateAndUseRecoveryCode validates and marks a recovery code as used. It always iterates all codes to prevent timing attacks that could reveal which code position matched.

type ResendVerificationRequest

type ResendVerificationRequest struct {
	Email string `json:"email" form:"email"`
}

ResendVerificationRequest is the request body for resending verification email.

type User

type User struct {
	bun.BaseModel   `bun:"table:users,alias:u"`
	UpdatedAt       time.Time    `bun:",nullzero" json:"updated_at" form:"-"`
	CreatedAt       time.Time    `bun:",nullzero,notnull,default:current_timestamp" json:"created_at" form:"-" verbose:"Created at"`
	EmailVerifiedAt *time.Time   `json:"email_verified_at,omitempty" form:"-"`
	Email           *string      `bun:",unique" json:"email,omitempty" form:"email" verbose:"Email"`
	Name            string       `bun:",nullzero" json:"name,omitempty" form:"name" verbose:"Name"`
	Bio             string       `bun:",nullzero" json:"bio,omitempty" form:"bio" verbose:"Bio"`
	Role            string       `bun:",notnull,default:'user'" json:"role" form:"role" verbose:"Role"`
	Username        string       `bun:",unique,notnull" json:"username" form:"username" verbose:"Username"`
	Credentials     []Credential `bun:"rel:has-many,join:id=user_id" json:"credentials,omitempty" form:"-"`
	ID              int64        `bun:",pk,autoincrement" json:"id" verbose:"ID"`
	EmailVerified   bool         `bun:",notnull,default:false" json:"email_verified" form:"-"`
	IsActive        bool         `bun:",notnull,default:true" json:"is_active" form:"is_active" verbose:"Active"`
}

User represents an authenticated user with WebAuthn credentials.

func CurrentUser added in v0.6.0

func CurrentUser(ctx context.Context) *User

CurrentUser retrieves the authenticated user from the context.

Example
package main

import (
	"context"
	"fmt"

	"github.com/oliverandrich/burrow/contrib/auth"
)

func main() {
	user := &auth.User{Username: "alice", Role: "admin"}
	ctx := auth.WithUser(context.Background(), user)

	u := auth.CurrentUser(ctx)
	fmt.Println(u.Username, u.Role)
}
Output:

alice admin

func UserFromContext

func UserFromContext(ctx context.Context) *User

UserFromContext is a deprecated alias for CurrentUser.

func (*User) IsAdmin

func (u *User) IsAdmin() bool

IsAdmin returns true if the user has the admin role.

func (User) String added in v0.5.0

func (u User) String() string

String returns the user's display name (Name if set, otherwise Username).

func (*User) WebAuthnCredentials

func (u *User) WebAuthnCredentials() []webauthn.Credential

WebAuthnCredentials returns the user's WebAuthn credentials.

func (*User) WebAuthnDisplayName

func (u *User) WebAuthnDisplayName() string

WebAuthnDisplayName returns the display name or falls back to username.

func (*User) WebAuthnID

func (u *User) WebAuthnID() []byte

WebAuthnID returns the user ID as bytes for the WebAuthn protocol.

func (*User) WebAuthnIcon

func (u *User) WebAuthnIcon() string

WebAuthnIcon returns an empty string (deprecated by the spec).

func (*User) WebAuthnName

func (u *User) WebAuthnName() string

WebAuthnName returns the username.

type WebAuthnService

type WebAuthnService interface {
	WebAuthn() *gowebauthn.WebAuthn
	StoreRegistrationSession(userID int64, data *gowebauthn.SessionData)
	GetRegistrationSession(userID int64) (*gowebauthn.SessionData, error)
	StoreDiscoverableSession(sessionID string, data *gowebauthn.SessionData)
	GetDiscoverableSession(sessionID string) (*gowebauthn.SessionData, error)
}

WebAuthnService defines WebAuthn operations.

func NewWebAuthnService

func NewWebAuthnService(ctx context.Context, rpDisplayName, rpID, rpOrigin string) (WebAuthnService, error)

NewWebAuthnService creates a new WebAuthn service with the given RP configuration. The context controls the lifetime of the background cleanup goroutine.

Directories

Path Synopsis
Package authtest provides test helpers for creating auth-migrated databases and test users, following the convention of net/http/httptest.
Package authtest provides test helpers for creating auth-migrated databases and test users, following the convention of net/http/httptest.

Jump to

Keyboard shortcuts

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