auth

package
v0.1.0 Latest Latest
Warning

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

Go to latest
Published: Apr 1, 2026 License: AGPL-3.0 Imports: 19 Imported by: 0

Documentation

Overview

internal/auth/cookie.go

Index

Constants

View Source
const (
	AttrKeyComponent   = logging.AttrKeyComponent
	AttrKeyOperation   = logging.AttrKeyOperation
	AttrKeyError       = logging.AttrKeyError
	AttrKeyUserID      = "user_id"
	AttrKeyDisplayName = "display_name"
	AttrKeySessionID   = "session_id"
	AttrKeyUsername    = "username"
)

Slog attribute key names for the auth domain. Use these constants when logging so keys are consistent and typo-safe across handlers and services.

View Source
const (
	BootstrapAdminUsername    = "admin"
	BootstrapAdminDisplayName = "Admin"
	BootstrapAdminEmail       = "admin@pulseweaver.invalid"
)
View Source
const CookieDuration = 7 * 24 * time.Hour

Variables

View Source
var (
	ErrInvalidCredentials       = errors.New("invalid credentials")
	ErrAdminCredentialsRequired = errors.New("admin credentials are required")
	ErrUsernameTaken            = errors.New("username already taken")
	ErrEmailTaken               = errors.New("email already taken")
	ErrUserNotFound             = errors.New("user not found")
	ErrInvalidUsername          = errors.New("invalid username")
	ErrInvalidDisplayName       = errors.New("invalid display name")
	ErrInvalidPassword          = errors.New("invalid password")
	ErrSelfDeleteForbidden      = errors.New("cannot delete yourself")
	ErrSelfRoleChangeForbidden  = errors.New("cannot change your own role")
	ErrNoUpdateFields           = errors.New("no fields to update")
)
View Source
var DefaultCookieConfig = CookieConfig{
	Name:     httpapi.SessionCookieName,
	Secure:   true,
	HTTPOnly: true,
	SameSite: http.SameSiteLaxMode,
	Domain:   "",
}

Default production config

Functions

func ExpireSessionCookie

func ExpireSessionCookie(cfg CookieConfig) *http.Cookie

ExpireSessionCookie creates a cookie to clear the session

func NewSessionCookie

func NewSessionCookie(token string, cfg CookieConfig) *http.Cookie

NewSessionCookie creates a standardized auth cookie

func PrincipalUserContextMiddleware

func PrincipalUserContextMiddleware(auth UserAuthenticator) func(http.Handler) http.Handler

PrincipalUserContextMiddleware resolves the authenticated principal into a user principal and injects it into the request context.

func TokenFromRequest

func TokenFromRequest(r *http.Request) (string, error)

func WithPrincipal

func WithPrincipal(ctx context.Context, principal Principal) context.Context

Types

type CookieConfig

type CookieConfig struct {
	Name     string
	Secure   bool
	HTTPOnly bool
	SameSite http.SameSite
	Domain   string // Empty for host-only (recommended)
}

CookieConfig holds environment-specific cookie settings

type HTTPHandler

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

func NewHandler

func NewHandler(service *Service, logger *slog.Logger) *HTTPHandler

func (*HTTPHandler) CreateUser

func (*HTTPHandler) DeleteUser

func (*HTTPHandler) DemoteUser

func (*HTTPHandler) Login

func (*HTTPHandler) UpdateMe

func (*HTTPHandler) UserAuthenticator

func (h *HTTPHandler) UserAuthenticator() UserAuthenticator

type Principal

type Principal struct {
	UserID    UserID
	SessionID SessionID
	Role      Role
}

func NewPrincipal

func NewPrincipal(userID UserID, sessionID SessionID, role Role) *Principal

func PrincipalFromContext

func PrincipalFromContext(ctx context.Context) (*Principal, bool)

func PrincipalFromSession

func PrincipalFromSession(session *SessionWithUser) *Principal

func (Principal) IsAdmin

func (principal Principal) IsAdmin() bool

type ProfileUpdates

type ProfileUpdates struct {
	DisplayName *string
	Username    *string
	Email       *string
}

type Repository

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

func NewRepository

func NewRepository(db *sqlx.DB) *Repository

func (*Repository) CountAdminUsers

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

func (*Repository) CountUsers

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

func (*Repository) CreateSession

func (r *Repository) CreateSession(ctx context.Context, session *Session) (*Session, error)

func (*Repository) CreateUser

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

func (*Repository) GetAllUsers

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

func (*Repository) GetSessionWithRoleByTokenHash

func (r *Repository) GetSessionWithRoleByTokenHash(ctx context.Context, tokenHash string) (*SessionWithUser, error)

GetSessionWithRoleByTokenHash Finds and retrieves valid session(non-expired or revoked) given a tokenHash. Also returns the user_role

func (*Repository) GetUserByID

func (r *Repository) GetUserByID(ctx context.Context, userID UserID) (*User, error)

func (*Repository) GetUserByUsername

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

func (*Repository) RevokeAllUserSessions

func (r *Repository) RevokeAllUserSessions(ctx context.Context, userID UserID) error

func (*Repository) RevokeAllUserSessionsExcept

func (r *Repository) RevokeAllUserSessionsExcept(ctx context.Context, userID UserID, exceptSessionID SessionID) error

func (*Repository) RevokeSessionByID

func (r *Repository) RevokeSessionByID(ctx context.Context, id SessionID) error

func (*Repository) RunInTx

func (r *Repository) RunInTx(ctx context.Context, fn func(repository) error) error

RunInTx runs the callback function inside a transaction. If already running in a transaction context, do not create a new one and reuse it

func (*Repository) SoftDeleteUser

func (r *Repository) SoftDeleteUser(ctx context.Context, userID UserID) error

func (*Repository) UpdatePasswordHash

func (r *Repository) UpdatePasswordHash(ctx context.Context, userID UserID, newHash []byte) error

func (*Repository) UpdateUser

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

type Role

type Role string
const AdminRole Role = "admin"
const UserRole Role = "user"

func (Role) String

func (r Role) String() string

type Service

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

func NewService

func NewService(repo repository, logger *slog.Logger) *Service

func (*Service) Authenticate

func (s *Service) Authenticate(ctx context.Context, rawToken string) (*Principal, error)

func (*Service) BootstrapAdmin

func (s *Service) BootstrapAdmin(ctx context.Context, conf config.ConfServer) error

func (*Service) ChangePassword

func (s *Service) ChangePassword(ctx context.Context, userID UserID, sessionID SessionID, currentPassword string, newPassword string) error

func (*Service) CreateUser

func (s *Service) CreateUser(ctx context.Context, username string, displayName string, email string, password string, principal *Principal) (*User, error)

func (*Service) DeleteUser

func (s *Service) DeleteUser(ctx context.Context, principal *Principal, targetID UserID) error

func (*Service) DemoteUser

func (s *Service) DemoteUser(ctx context.Context, principal *Principal, targetID UserID) (*User, error)

func (*Service) GetUserFromPrincipal

func (s *Service) GetUserFromPrincipal(ctx context.Context, principal *Principal) (*User, error)

func (*Service) ListUsers

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

func (*Service) Login

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

func (*Service) PromoteUser

func (s *Service) PromoteUser(ctx context.Context, principal *Principal, targetID UserID) (*User, error)

func (*Service) RevokeSession

func (s *Service) RevokeSession(ctx context.Context, sessionID SessionID) error

func (*Service) UpdateOwnProfile

func (s *Service) UpdateOwnProfile(ctx context.Context, userID UserID, updates ProfileUpdates) (*User, error)

type Session

type Session struct {
	ID         SessionID  `db:"id" `
	UserID     UserID     `db:"user_id" `
	TokenHash  string     `db:"token_hash" `
	CreatedAt  time.Time  `db:"created_at" `
	ExpiresAt  time.Time  `db:"expires_at" `
	LastUsedAt *time.Time `db:"last_used_at" `
	RevokedAt  *time.Time `db:"revoked_at" `
}

func NewSession

func NewSession(userID UserID, tokenHash string) Session

type SessionID

type SessionID int64

func (SessionID) Int64

func (id SessionID) Int64() int64

func (SessionID) String

func (id SessionID) String() string

type SessionWithUser

type SessionWithUser struct {
	Session
	UserRole Role `db:"user_role"` // Alias in SQL Join
}

type User

type User struct {
	ID                 UserID     `db:"id"`
	Username           string     `db:"username"`
	DisplayName        string     `db:"display_name"`
	Email              string     `db:"email"`
	PasswordHash       []byte     `db:"password_hash"`
	Role               Role       `db:"role"`
	MustChangePassword bool       `db:"must_change_password"`
	CreatedBy          *UserID    `db:"created_by"`
	CreatedAt          time.Time  `db:"created_at"`
	DeletedAt          *time.Time `db:"deleted_at"`
}

func NewUser

func NewUser(
	username string,
	displayName string,
	email string,
	password string,
	role Role,
	createdByID *UserID,
) (User, error)

func (*User) Update

func (u *User) Update(up ProfileUpdates) error

type UserAuthenticator

type UserAuthenticator interface {
	Authenticate(ctx context.Context, token string) (*Principal, error)
}

UserAuthenticator defines the interface for authenticating user sessions. This interface is defined in the auth package to avoid import cycles.

type UserID

type UserID int64

func (UserID) Int64

func (id UserID) Int64() int64

func (UserID) String

func (id UserID) String() string

Jump to

Keyboard shortcuts

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