auth

package
v0.7.4 Latest Latest
Warning

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

Go to latest
Published: Aug 21, 2026 License: MIT Imports: 16 Imported by: 0

Documentation

Overview

Package auth is chatz's authentication domain: password hashing (bcrypt), server-side opaque session tokens (only the SHA-256 hash is stored; the raw token lives in the client's HttpOnly cookie), first-run admin bootstrap, and optional single-user passwordless auto-login. Handlers call this layer; it owns the users + sessions tables.

Index

Constants

View Source
const (
	// CookieName is the session cookie holding the raw opaque token.
	CookieName = "chatz_session"
)

Variables

View Source
var (
	// ErrInvalidCredentials is returned for an unknown user or a bad password.
	// Deliberately indistinguishable between the two (no user enumeration).
	ErrInvalidCredentials = errors.New("auth: invalid credentials")

	// ErrInvalidInput is returned for an empty username or password where one
	// is required.
	ErrInvalidInput = errors.New("auth: invalid input")

	// ErrUserExists is returned when the username is already taken.
	ErrUserExists = errors.New("auth: username already exists")

	// ErrSetupClosed is returned by Bootstrap once at least one user exists.
	ErrSetupClosed = errors.New("auth: setup already completed")

	// ErrSessionInvalid is returned for a missing, revoked, or expired session.
	ErrSessionInvalid = errors.New("auth: session invalid or expired")

	// ErrPasswordlessUnavailable is returned when passwordless auto-login is
	// disabled or the install is not a single-user one.
	ErrPasswordlessUnavailable = errors.New("auth: passwordless not available")
)

Auth domain errors. The HTTP layer maps these to status codes (invalid credentials + invalid session -> 401, user-exists + setup-closed -> 409, invalid input -> 400). Declared with errors.New so they stay comparable across ctxerrors.Wrap layers via errors.Is.

Functions

func UserToAPI

func UserToAPI(u *models.User) api.User

UserToAPI projects a stored user row to the wire shape. PasswordHash is never exposed.

Types

type Service

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

Service is the auth domain service. Construct with New and share it — it is stateless beyond its query handle and config.

func New

func New(q *repositories.Query, passwordless bool) *Service

New builds the Service over the given query handle. passwordless enables single-user auto-login (see PasswordlessLogin).

func (*Service) Authenticate

func (s *Service) Authenticate(
	ctx context.Context,
	token string,
) (*models.User, error)

Authenticate resolves a raw session token to its user, or ErrSessionInvalid if the session is missing, expired, or its user is gone.

func (*Service) Bootstrap

func (s *Service) Bootstrap(
	ctx context.Context,
	username, password string,
) (*models.User, error)

Bootstrap creates the first user as admin. It fails with ErrSetupClosed once any user exists, and ErrInvalidInput without a password (the admin must have one — passwordless is opt-in per-config, not for the bootstrap account).

func (*Service) CreateUser

func (s *Service) CreateUser(
	ctx context.Context,
	username, password string,
	isAdmin bool,
) (*models.User, error)

CreateUser provisions a user. An empty password creates a passwordless account (login only via PasswordlessLogin). Returns ErrUserExists if the username is taken, ErrInvalidInput if it's empty.

func (*Service) DeleteUser

func (s *Service) DeleteUser(ctx context.Context, id uuid.UUID) error

DeleteUser removes the user with id; the DB cascades their sessions + chats. Returns commerr.ErrNotFound when no user has that id.

func (*Service) ListUsers

func (s *Service) ListUsers(ctx context.Context) ([]*models.User, error)

ListUsers returns every user ordered by creation time (admin view).

func (*Service) Login

func (s *Service) Login(
	ctx context.Context,
	username, password string,
) (string, *models.User, error)

Login verifies the password and issues a session, returning the raw token to set as a cookie. Unknown user and bad password both return ErrInvalidCredentials (no user enumeration).

func (*Service) Logout

func (s *Service) Logout(ctx context.Context, token string) error

Logout revokes the session for the given raw token. A missing session is not an error — logout is idempotent.

func (*Service) NeedsSetup

func (s *Service) NeedsSetup(ctx context.Context) (bool, error)

NeedsSetup reports whether the install has no users yet (first-run).

func (*Service) PasswordlessLogin

func (s *Service) PasswordlessLogin(
	ctx context.Context,
) (string, *models.User, error)

PasswordlessLogin issues a session without a password, but ONLY when passwordless is enabled AND the install has exactly one user. Otherwise ErrPasswordlessUnavailable — it must never silently pick an account on a multi-user install.

Jump to

Keyboard shortcuts

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