auth

package
v0.18.1 Latest Latest
Warning

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

Go to latest
Published: May 6, 2026 License: MIT Imports: 34 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 = den.ErrNotFound

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 µCSS 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) AcknowledgeRecoveryCodes added in v0.11.0

func (a *App) AcknowledgeRecoveryCodes(w http.ResponseWriter, r *http.Request) error

AcknowledgeRecoveryCodes clears recovery codes from the session and redirects.

func (*App) AddCredentialBegin added in v0.11.0

func (a *App) AddCredentialBegin(w http.ResponseWriter, r *http.Request) error

AddCredentialBegin starts the process of adding a new credential.

func (*App) AddCredentialFinish added in v0.11.0

func (a *App) AddCredentialFinish(w http.ResponseWriter, r *http.Request) error

AddCredentialFinish completes adding a new credential.

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(cfg *burrow.AppConfig, cmd *cli.Command) error

func (*App) CredentialsPage added in v0.11.0

func (a *App) CredentialsPage(w http.ResponseWriter, r *http.Request) error

CredentialsPage renders the credentials management page.

func (*App) DeleteCredential added in v0.11.0

func (a *App) DeleteCredential(w http.ResponseWriter, r *http.Request) error

DeleteCredential removes a credential.

func (*App) Dependencies

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

func (*App) Documents added in v0.11.0

func (a *App) Documents() []any

Documents returns the Den document types registered by this app.

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) IsInviteOnly added in v0.11.0

func (a *App) IsInviteOnly() bool

IsInviteOnly returns true if invite-only registration is enabled.

func (*App) LoginBegin added in v0.11.0

func (a *App) LoginBegin(w http.ResponseWriter, r *http.Request) error

LoginBegin starts the WebAuthn discoverable login process.

func (*App) LoginFinish added in v0.11.0

func (a *App) LoginFinish(w http.ResponseWriter, r *http.Request) error

LoginFinish completes the WebAuthn discoverable login.

func (*App) LoginPage added in v0.11.0

func (a *App) LoginPage(w http.ResponseWriter, r *http.Request) error

LoginPage renders the login page.

func (*App) Logout added in v0.11.0

func (a *App) Logout(w http.ResponseWriter, r *http.Request) error

Logout clears the session cookie.

func (*App) Middleware

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

func (*App) Name

func (a *App) Name() string

func (*App) RecoveryCodesPage added in v0.11.0

func (a *App) RecoveryCodesPage(w http.ResponseWriter, r *http.Request) error

RecoveryCodesPage renders the dedicated recovery codes page.

func (*App) RecoveryLogin added in v0.11.0

func (a *App) RecoveryLogin(w http.ResponseWriter, r *http.Request) error

RecoveryLogin authenticates a user with a recovery code.

func (*App) RecoveryPage added in v0.11.0

func (a *App) RecoveryPage(w http.ResponseWriter, r *http.Request) error

RecoveryPage renders the recovery login page.

func (*App) RegenerateRecoveryCodes added in v0.11.0

func (a *App) RegenerateRecoveryCodes(w http.ResponseWriter, r *http.Request) error

RegenerateRecoveryCodes generates new recovery codes and invalidates old ones.

func (*App) RegisterBegin added in v0.11.0

func (a *App) RegisterBegin(w http.ResponseWriter, r *http.Request) error

RegisterBegin starts the WebAuthn registration process.

func (*App) RegisterFinish added in v0.11.0

func (a *App) RegisterFinish(w http.ResponseWriter, r *http.Request) error

RegisterFinish completes the WebAuthn registration process.

func (*App) RegisterJobs

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

RegisterJobs registers auth email job handlers with the queue. Skipped when no email service is configured (WithEmailService was not called), since there is nothing to deliver.

func (*App) RegisterPage added in v0.11.0

func (a *App) RegisterPage(w http.ResponseWriter, r *http.Request) error

RegisterPage renders the registration page.

func (*App) Repo

func (a *App) Repo() *Repository

Repo returns the auth repository for external access.

func (*App) RequestFuncMap

func (a *App) RequestFuncMap(ctx context.Context) template.FuncMap

RequestFuncMap returns request-scoped template functions for auth state.

func (*App) RequireAdmin added in v0.13.0

func (a *App) RequireAdmin() func(http.Handler) http.Handler

RequireAdmin satisfies the burrow.AdminAuth interface.

func (*App) RequireAuth added in v0.13.0

func (a *App) RequireAuth() func(http.Handler) http.Handler

RequireAuth satisfies the burrow.AdminAuth interface so the admin app can discover auth middleware from the registry without importing this package.

func (*App) ResendVerification added in v0.11.0

func (a *App) ResendVerification(w http.ResponseWriter, r *http.Request) error

ResendVerification resends the verification email.

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) Start added in v0.10.0

func (a *App) Start(_ *burrow.Server) error

Start launches the background cleanup goroutine after the full boot sequence completes. This ensures the goroutine only runs when the server has started successfully.

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.

func (*App) UseEmailMode added in v0.11.0

func (a *App) UseEmailMode() bool

UseEmailMode returns true if email-based authentication is enabled.

func (*App) VerifyEmail added in v0.11.0

func (a *App) VerifyEmail(w http.ResponseWriter, r *http.Request) error

VerifyEmail handles the email verification link.

func (*App) VerifyPendingPage added in v0.11.0

func (a *App) VerifyPendingPage(w http.ResponseWriter, r *http.Request) error

VerifyPendingPage renders the "check your email" page.

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 {
	document.Base
	CredentialID    []byte `json:"credential_id" den:"unique"`
	PublicKey       []byte `json:"public_key"`
	AAGUID          []byte `json:"aaguid"`
	AttestationType string `json:"attestation_type"`
	Transports      string `json:"transports"`
	Name            string `json:"name"`
	UserID          string `json:"user_id" den:"index"`
	SignCount       uint32 `json:"sign_count"`
	BackupState     bool   `json:"backup_state"`
	BackupEligible  bool   `json:"backup_eligible"`
}

Credential stores a WebAuthn credential for a user.

func NewCredentialFromWebAuthn

func NewCredentialFromWebAuthn(userID string, 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 {
	document.Base
	ExpiresAt time.Time `json:"expires_at"`
	TokenHash string    `json:"token_hash" den:"unique"`
	UserID    string    `json:"user_id" den:"index"`
}

EmailVerificationToken stores a hashed token for email verification.

type Invite

type Invite struct {
	document.Base
	ExpiresAt time.Time  `json:"expires_at" form:"-" verbose:"Expires at"`
	UsedAt    *time.Time `json:"used_at,omitempty" form:"-"`
	UsedBy    *string    `json:"used_by,omitempty" form:"-"`
	CreatedBy *string    `json:"created_by,omitempty" form:"-"`
	Email     string     `json:"email" verbose:"Email"`
	Label     string     `json:"label" verbose:"Label"`
	TokenHash string     `json:"token_hash" den:"unique" form:"-"`
}

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 {
	document.Base
	UsedAt   *time.Time `json:"used_at,omitempty"`
	CodeHash string     `json:"code_hash"`
	UserID   string     `json:"user_id" den:"index,index_together:recovery_status"`
	Used     bool       `json:"used" den:"index_together:recovery_status"`
}

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 *den.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 string) (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 string, 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 string, 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 string) error

DeleteCredential deletes a credential.

func (*Repository) DeleteEmailVerificationToken

func (r *Repository) DeleteEmailVerificationToken(ctx context.Context, tokenID string) 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 string) error

DeleteInvite deletes an invite (revoke).

func (*Repository) DeleteRecoveryCodes

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

DeleteRecoveryCodes deletes all recovery codes for a user.

func (*Repository) DeleteUser

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

DeleteUser permanently deletes a user by ID.

func (*Repository) DeleteUserEmailVerificationTokens

func (r *Repository) DeleteUserEmailVerificationTokens(ctx context.Context, userID string) 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 string) ([]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) GetInviteByID added in v0.13.0

func (r *Repository) GetInviteByID(ctx context.Context, id string) (*Invite, error)

GetInviteByID retrieves an invite by its ID.

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 string) (int64, error)

GetUnusedRecoveryCodeCount returns the count of unused recovery codes.

func (*Repository) GetUnusedRecoveryCodes

func (r *Repository) GetUnusedRecoveryCodes(ctx context.Context, userID string) ([]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 string) (*User, error)

GetUserByID retrieves a user by ID.

func (*Repository) GetUserByIDWithCredentials

func (r *Repository) GetUserByIDWithCredentials(ctx context.Context, id string) (*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 string) (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) ListInvitesPaged added in v0.13.0

func (r *Repository) ListInvitesPaged(ctx context.Context, pr burrow.PageRequest) ([]Invite, burrow.PageResult, error)

ListInvitesPaged returns invites with pagination, ordered by created_at desc.

func (*Repository) ListUsers

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

ListUsers returns all users ordered by creation time ascending.

func (*Repository) ListUsersPaged added in v0.13.0

func (r *Repository) ListUsersPaged(ctx context.Context, pr burrow.PageRequest, role string) ([]User, burrow.PageResult, error)

ListUsersPaged returns users with pagination and optional role filter, ordered by created_at desc.

func (*Repository) MarkEmailVerified

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

MarkEmailVerified marks a user's email as verified.

func (*Repository) MarkInviteUsed

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

MarkInviteUsed atomically marks an invite as used by the given user. The condition used_at IS NULL 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 string) 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) SearchInvitesPaged added in v0.18.0

func (r *Repository) SearchInvitesPaged(ctx context.Context, query string, pr burrow.PageRequest) ([]Invite, burrow.PageResult, error)

SearchInvitesPaged searches invites by label or email with pagination, ordered by created_at desc.

func (*Repository) SearchUsers added in v0.13.0

func (r *Repository) SearchUsers(ctx context.Context, query string, pr burrow.PageRequest, role string) ([]User, burrow.PageResult, error)

SearchUsers searches users by username, name, or email with pagination and optional role filter.

func (*Repository) SetUserActive

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

SetUserActive sets a user's is_active flag.

func (*Repository) SetUserRole

func (r *Repository) SetUserRole(ctx context.Context, userID string, 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 string, 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 {
	document.Base
	EmailVerifiedAt *time.Time   `json:"email_verified_at,omitempty" form:"-"`
	Email           *string      `json:"email,omitempty" den:"unique" form:"email" verbose:"Email"`
	Name            string       `json:"name,omitempty" form:"name" verbose:"Name"`
	Bio             string       `json:"bio,omitempty" form:"bio" verbose:"Bio"`
	Role            string       `json:"role" den:"index" form:"role" verbose:"Role"`
	Username        string       `json:"username" den:"unique" form:"username" verbose:"Username"`
	Credentials     []Credential `json:"credentials,omitempty" form:"-"` // populated by separate query, not embedded
	EmailVerified   bool         `json:"email_verified" form:"-"`
	IsActive        bool         `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 MustCurrentUser added in v0.9.0

func MustCurrentUser(ctx context.Context) *User

MustCurrentUser returns the authenticated user from the context. It panics if no user is present — only use in handlers protected by RequireAuth middleware.

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. The ULID string is unique and stable, so we use it directly.

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 string, data *gowebauthn.SessionData)
	GetRegistrationSession(userID string) (*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