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 ¶
- Constants
- Variables
- func DefaultAuthLayout() string
- func DefaultEmailRenderer() authmail.Renderer
- func GenerateInviteToken() (plaintext, hash string, err error)
- func GenerateToken() (string, string, time.Time, error)
- func HashToken(token string) string
- func IsAuthenticated(ctx context.Context) bool
- func Logo(ctx context.Context) template.HTML
- func LogoFromContext(ctx context.Context) template.HTML
- func NormalizeCode(code string) string
- func RequireAdmin() func(http.Handler) http.Handler
- func RequireAuth() func(http.Handler) http.Handler
- func SafeRedirectPath(next, defaultPath string) string
- func TransportsFromWebAuthn(transports []protocol.AuthenticatorTransport) string
- func WithLogo(ctx context.Context, logo template.HTML) context.Context
- func WithUser(ctx context.Context, user *User) context.Context
- type App
- func (a *App) AdminNavItems() []burrow.NavItem
- func (a *App) AdminRoutes(r chi.Router)
- func (a *App) CLICommands() []*cli.Command
- func (a *App) Configure(cmd *cli.Command) error
- func (a *App) Dependencies() []string
- func (a *App) Flags(configSource func(key string) cli.ValueSource) []cli.Flag
- func (a *App) FuncMap() template.FuncMap
- func (a *App) Handlers() *Handlers
- func (a *App) Middleware() []func(http.Handler) http.Handler
- func (a *App) MigrationFS() fs.FS
- func (a *App) Name() string
- func (a *App) Register(cfg *burrow.AppConfig) error
- func (a *App) RegisterJobs(q burrow.Queue)
- func (a *App) Repo() *Repository
- func (a *App) RequestFuncMap(r *http.Request) template.FuncMap
- func (a *App) Routes(r chi.Router)
- func (a *App) Shutdown(_ context.Context) error
- func (a *App) StaticFS() (string, fs.FS)
- func (a *App) TemplateFS() fs.FS
- func (a *App) TranslationFS() fs.FS
- type Config
- type CreateInviteRequest
- type Credential
- type EmailService
- type EmailVerificationToken
- type Handlers
- func (h *Handlers) AcknowledgeRecoveryCodes(w http.ResponseWriter, r *http.Request) error
- func (h *Handlers) AddCredentialBegin(w http.ResponseWriter, r *http.Request) error
- func (h *Handlers) AddCredentialFinish(w http.ResponseWriter, r *http.Request) error
- func (h *Handlers) CredentialsPage(w http.ResponseWriter, r *http.Request) error
- func (h *Handlers) DeleteCredential(w http.ResponseWriter, r *http.Request) error
- func (h *Handlers) IsInviteOnly() bool
- func (h *Handlers) LoginBegin(w http.ResponseWriter, r *http.Request) error
- func (h *Handlers) LoginFinish(w http.ResponseWriter, r *http.Request) error
- func (h *Handlers) LoginPage(w http.ResponseWriter, r *http.Request) error
- func (h *Handlers) Logout(w http.ResponseWriter, r *http.Request) error
- func (h *Handlers) RecoveryCodesPage(w http.ResponseWriter, r *http.Request) error
- func (h *Handlers) RecoveryLogin(w http.ResponseWriter, r *http.Request) error
- func (h *Handlers) RecoveryPage(w http.ResponseWriter, r *http.Request) error
- func (h *Handlers) RegenerateRecoveryCodes(w http.ResponseWriter, r *http.Request) error
- func (h *Handlers) RegisterBegin(w http.ResponseWriter, r *http.Request) error
- func (h *Handlers) RegisterFinish(w http.ResponseWriter, r *http.Request) error
- func (h *Handlers) RegisterPage(w http.ResponseWriter, r *http.Request) error
- func (h *Handlers) ResendVerification(w http.ResponseWriter, r *http.Request) error
- func (h *Handlers) UseEmailMode() bool
- func (h *Handlers) VerifyEmail(w http.ResponseWriter, r *http.Request) error
- func (h *Handlers) VerifyPendingPage(w http.ResponseWriter, r *http.Request) error
- type Invite
- type Option
- type RecoveryCode
- type RecoveryLoginRequest
- type RecoveryService
- type RegisterBeginRequest
- type Renderer
- type Repository
- func (r *Repository) CountAdminUsers(ctx context.Context) (int, error)
- func (r *Repository) CountUserCredentials(ctx context.Context, userID int64) (int64, error)
- func (r *Repository) CountUsers(ctx context.Context) (int, error)
- func (r *Repository) CreateCredential(ctx context.Context, cred *Credential) error
- func (r *Repository) CreateEmailVerificationToken(ctx context.Context, userID int64, tokenHash string, expiresAt time.Time) error
- func (r *Repository) CreateInvite(ctx context.Context, invite *Invite) error
- func (r *Repository) CreateRecoveryCodes(ctx context.Context, userID int64, codeHashes []string) error
- func (r *Repository) CreateUser(ctx context.Context, username, name string) (*User, error)
- func (r *Repository) CreateUserWithEmail(ctx context.Context, email, name string) (*User, error)
- func (r *Repository) DeleteCredential(ctx context.Context, credID, userID int64) error
- func (r *Repository) DeleteEmailVerificationToken(ctx context.Context, tokenID int64) error
- func (r *Repository) DeleteExpiredEmailVerificationTokens(ctx context.Context) error
- func (r *Repository) DeleteInvite(ctx context.Context, inviteID int64) error
- func (r *Repository) DeleteRecoveryCodes(ctx context.Context, userID int64) error
- func (r *Repository) DeleteUser(ctx context.Context, id int64) error
- func (r *Repository) DeleteUserEmailVerificationTokens(ctx context.Context, userID int64) error
- func (r *Repository) EmailExists(ctx context.Context, email string) (bool, error)
- func (r *Repository) GetCredentialsByUserID(ctx context.Context, userID int64) ([]Credential, error)
- func (r *Repository) GetEmailVerificationToken(ctx context.Context, tokenHash string) (*EmailVerificationToken, error)
- func (r *Repository) GetInviteByTokenHash(ctx context.Context, tokenHash string) (*Invite, error)
- func (r *Repository) GetUnusedRecoveryCodeCount(ctx context.Context, userID int64) (int64, error)
- func (r *Repository) GetUnusedRecoveryCodes(ctx context.Context, userID int64) ([]RecoveryCode, error)
- func (r *Repository) GetUserByEmail(ctx context.Context, email string) (*User, error)
- func (r *Repository) GetUserByID(ctx context.Context, id int64) (*User, error)
- func (r *Repository) GetUserByIDWithCredentials(ctx context.Context, id int64) (*User, error)
- func (r *Repository) GetUserByUsername(ctx context.Context, username string) (*User, error)
- func (r *Repository) HasRecoveryCodes(ctx context.Context, userID int64) (bool, error)
- func (r *Repository) ListInvites(ctx context.Context) ([]Invite, error)
- func (r *Repository) ListUsers(ctx context.Context) ([]User, error)
- func (r *Repository) MarkEmailVerified(ctx context.Context, userID int64) error
- func (r *Repository) MarkInviteUsed(ctx context.Context, inviteID, userID int64) error
- func (r *Repository) MarkRecoveryCodeUsed(ctx context.Context, codeID int64) error
- func (r *Repository) PurgeOrphanedUsers(ctx context.Context, olderThan time.Duration) (int, error)
- func (r *Repository) SetUserActive(ctx context.Context, userID int64, active bool) error
- func (r *Repository) SetUserRole(ctx context.Context, userID int64, role string) error
- func (r *Repository) UpdateCredentialSignCount(ctx context.Context, credentialID []byte, signCount uint32) error
- func (r *Repository) UpdateUser(ctx context.Context, user *User) error
- func (r *Repository) UserExists(ctx context.Context, username string) (bool, error)
- func (r *Repository) ValidateAndUseRecoveryCode(ctx context.Context, userID int64, code string) (bool, error)
- type ResendVerificationRequest
- type User
- type WebAuthnService
Examples ¶
Constants ¶
const ( RoleUser = "user" RoleAdmin = "admin" )
Role constants.
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 )
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 ¶
var ErrInviteAlreadyUsed = errors.New("invite already used")
ErrInviteAlreadyUsed is returned when an invite has already been consumed.
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 ¶
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 ¶
GenerateInviteToken generates a random invite token and its SHA256 hash.
func GenerateToken ¶
GenerateToken generates a new verification token. Returns (plaintext token, SHA256 hash for storage, expiry time, error).
func IsAuthenticated ¶
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 LogoFromContext ¶
LogoFromContext is a deprecated alias for Logo.
func NormalizeCode ¶
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 ¶
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 ¶
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 ¶
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.
Types ¶
type App ¶
type App struct {
// contains filtered or unexported fields
}
App implements the auth contrib app.
func New ¶
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 ¶
AdminNavItems returns navigation items for the admin panel.
func (*App) AdminRoutes ¶
AdminRoutes registers admin routes for user and invite management. The router is expected to already have auth middleware applied.
func (*App) CLICommands ¶
CLICommands returns auth-related CLI subcommands (promote, demote, create-invite).
func (*App) Dependencies ¶
func (*App) MigrationFS ¶
func (*App) RegisterJobs ¶
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 ¶
RequestFuncMap returns request-scoped template functions for auth state.
func (*App) Shutdown ¶
Shutdown stops the background cleanup goroutine. Safe to call multiple times or if Configure was never called.
func (*App) StaticFS ¶
StaticFS returns the embedded static assets (webauthn.js) under the "auth" prefix.
func (*App) TemplateFS ¶
TemplateFS returns the embedded HTML template files.
func (*App) TranslationFS ¶
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 ¶
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 ¶
AcknowledgeRecoveryCodes clears recovery codes from the session and redirects.
func (*Handlers) AddCredentialBegin ¶
AddCredentialBegin starts the process of adding a new credential.
func (*Handlers) AddCredentialFinish ¶
AddCredentialFinish completes adding a new credential.
func (*Handlers) CredentialsPage ¶
CredentialsPage renders the credentials management page.
func (*Handlers) DeleteCredential ¶
DeleteCredential removes a credential.
func (*Handlers) IsInviteOnly ¶
IsInviteOnly returns true if invite-only registration is enabled.
func (*Handlers) LoginBegin ¶
LoginBegin starts the WebAuthn discoverable login process.
func (*Handlers) LoginFinish ¶
LoginFinish completes the WebAuthn discoverable login.
func (*Handlers) RecoveryCodesPage ¶
RecoveryCodesPage renders the dedicated recovery codes page. Codes are read from the session; if none are present, redirects to login redirect.
func (*Handlers) RecoveryLogin ¶
RecoveryLogin authenticates a user with a recovery code.
func (*Handlers) RecoveryPage ¶
RecoveryPage renders the recovery login page.
func (*Handlers) RegenerateRecoveryCodes ¶
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 ¶
RegisterBegin starts the WebAuthn registration process.
func (*Handlers) RegisterFinish ¶
RegisterFinish completes the WebAuthn registration process.
func (*Handlers) RegisterPage ¶
RegisterPage renders the registration page.
func (*Handlers) ResendVerification ¶
ResendVerification resends the verification email.
func (*Handlers) UseEmailMode ¶
UseEmailMode returns true if email-based authentication is enabled.
func (*Handlers) VerifyEmail ¶
VerifyEmail handles the email verification link.
func (*Handlers) VerifyPendingPage ¶
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.
type Option ¶
type Option func(*App)
Option configures the auth app.
func WithAuthLayout ¶
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 ¶
WithLogoComponent sets an optional logo HTML rendered above auth page content. When set, the logo appears on login, register, and recovery pages.
func WithRenderer ¶
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 ¶
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 ¶
CreateUser creates a new user with a username and optional name.
func (*Repository) CreateUserWithEmail ¶
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 ¶
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 ¶
GetInviteByTokenHash retrieves an invite by its token hash.
func (*Repository) GetUnusedRecoveryCodeCount ¶
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 ¶
GetUserByEmail retrieves a user by email.
func (*Repository) GetUserByID ¶
GetUserByID retrieves a user by ID.
func (*Repository) GetUserByIDWithCredentials ¶
GetUserByIDWithCredentials retrieves a user by ID with preloaded credentials.
func (*Repository) GetUserByUsername ¶
GetUserByUsername retrieves a user by username.
func (*Repository) HasRecoveryCodes ¶
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 ¶
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 ¶
SetUserActive sets a user's is_active flag.
func (*Repository) SetUserRole ¶
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 ¶
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
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 ¶
UserFromContext is a deprecated alias for CurrentUser.
func (User) String ¶ added in v0.5.0
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 ¶
WebAuthnDisplayName returns the display name or falls back to username.
func (*User) WebAuthnID ¶
WebAuthnID returns the user ID as bytes for the WebAuthn protocol.
func (*User) WebAuthnIcon ¶
WebAuthnIcon returns an empty string (deprecated by the spec).
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.
Source Files
¶
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. |