session

package
v0.4.0 Latest Latest
Warning

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

Go to latest
Published: Apr 2, 2026 License: MIT Imports: 15 Imported by: 0

README

session

Session-based authentication, type-safe cookies, and flash messages.

Installation

go get github.com/eriicafes/httpx

Session-based Authentication

Session-based authentication following the Lucia Auth guide for secure session management.

Features:

  • Secure session token generation and validation
  • Generic types for session and user data
  • Automatic session refresh
  • Token store (default cookie store or custom)
  • Optimistic validation with cached sessions (optional)
Basic Usage
import (
    "net/http"
    "time"
    "github.com/eriicafes/httpx"
    "github.com/eriicafes/httpx/session"
)

// Define your session and user types
type Session struct {
    ID         string
    UserID     string
    SecretHash []byte `json:"-"` // Never send secret hash to client
    ExpiresAt  time.Time
}

func (s Session) GetSession() (string, []byte, time.Time) {
    return s.ID, s.SecretHash, s.ExpiresAt
}

type User struct {
    ID   string
    Name string
}

// Implement SessionStore
type MySessionStore struct {
    // your database connection
}

func (s *MySessionStore) GetSessionAndUser(sessionId string) (Session, User, error) {
    // retrieve session and user from database
}

func (s *MySessionStore) CreateSession(sessionData session.Session, user User) (Session, error) {
    // create session in database
}

func (s *MySessionStore) UpdateSession(sessionId string, expiresAt time.Time) (Session, error) {
    // update session expiration
}

func (s *MySessionStore) DeleteSession(sessionId string) error {
    // delete session from database
}

func (s *MySessionStore) DeleteUserSessions(user User) error {
    // delete all sessions for user
}

// Create auth instance
store := &MySessionStore{}
auth, err := session.NewAuth(store)

// CSRF protection
csrf := http.NewCrossOriginProtection()

mux := httpx.Use(http.NewServeMux(), csrf.Handler)

mux.Route("POST /login", loginHandler)
mux.Route("POST /logout", logoutHandler)
Login
func loginHandler(w http.ResponseWriter, r *http.Request) {
    // Validate credentials
    user := authenticateUser(r)

    // LoginRequest creates a new session and sets the session token in the response
    session, err := auth.LoginRequest(w, user)
    if err != nil {
        http.Error(w, "Login failed", http.StatusInternalServerError)
        return
    }

    fmt.Fprintf(w, "Logged in successfully")
}
Protected Routes
func protectedHandler(w http.ResponseWriter, r *http.Request) {
    // AuthenticateRequest gets the session token from request, validates it, and returns session and user
    // Automatically refreshes the session and updates the token in the response
    session, user, err := auth.AuthenticateRequest(w, r)
    if err != nil {
        http.Error(w, "Unauthorized", http.StatusUnauthorized)
        return
    }

    // Use session and user data
    fmt.Fprintf(w, "Welcome, %s!", user.Name)
}
Logout
func logoutHandler(w http.ResponseWriter, r *http.Request) {
    // LogoutRequest gets the session token from request, validates it, deletes the session, and removes the token
    session, user, err := auth.LogoutRequest(w, r)
    if err != nil {
        http.Error(w, "Logout failed", http.StatusInternalServerError)
        return
    }

    fmt.Fprintf(w, "Logged out successfully")
}
Session Management

For custom flows, use the manual session methods below. The LoginRequest, AuthenticateRequest, and LogoutRequest methods shown above are convenience helpers that combine these operations.

// Login flow
sessionToken, session, err := auth.CreateSession(user)
err = auth.SetSessionToken(w, sessionToken, session, user)

// Authentication flow
sessionToken, err := auth.GetSessionToken(r)
session, user, optimistic, err := auth.ValidateSessionToken(sessionToken)
// Update token store if not optimistic
if !optimistic {
    err = auth.SetSessionToken(w, sessionToken, session, user)
}

// Logout flow - single session
sessionToken, err := auth.GetSessionToken(r)
sessionId, _ := session.ParseSessionToken(sessionToken)
auth.InvalidateSession(sessionId)
auth.DeleteSessionToken(w)

// Logout flow - all user sessions (e.g., "logout from all devices")
sessionToken, err := auth.GetSessionToken(r)
session, user, _, err := auth.ValidateSessionToken(sessionToken)
auth.InvalidateAllSessions(user)
auth.DeleteSessionToken(w)
CSRF Protection

For cookie-based authentication, SameSite=Lax limits when session cookies are sent, while Go's origin-based CSRF protection blocks non-safe cross-origin browser requests (including those from other subdomains). Together, they provide protection against CSRF, provided that safe HTTP methods are never used to perform state-changing actions.

Use Go 1.25's http.NewCrossOriginProtection() to block cross-origin requests:

csrf := http.NewCrossOriginProtection()

// Trust additional origins
csrf.AddTrustedOrigin("https://app.example.com")

// Use a custom error response
csrf.SetDenyHandler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    httpx.SendStatus(w, http.StatusForbidden, httpx.JSON{
        "error": "invalid_origin",
    })
}))

mux := httpx.Use(http.NewServeMux(), csrf.Handler)

Cross-origin requests are detected with the Sec-Fetch-Site header or by comparing the hostname of the Origin header with Host header. GET requests are always allowed.

For more details, see the http.CrossOriginProtection documentation.

Advanced Usage
Token Stores

Token stores handle how session tokens are stored and retrieved from HTTP requests/responses.

The package provides two built-in cookie-based token stores:

CookieTokenStore (Default)

Basic unsigned cookie storage that stores only the session ID. Requires lookup on every request.

tokenStore, err := session.NewCookieTokenStore(
    session.WithCookieName("auth_session"),
    session.WithCookieSecure(false) // For development only
)

auth, err := session.NewAuth(store,
    session.WithTokenStore(tokenStore),
)

Note: If no token store is specified, NewAuth uses CookieTokenStore by default.

TrustedCookieTokenStore (Optimistic)

Encrypted cookie storage that caches session and user data. Enables optimistic authentication without lookups until the cache becomes stale.

secret := session.Secret([]byte("your-secret-key"))

// Trust cached data for 15 minutes before session revalidation
tokenStore, err := session.NewTrustedCookieTokenStore[Session, User](
    secret,
    time.Minute * 15, // Stale duration
    session.WithCookieName("auth_session"),
    session.WithCookieSecure(false) // For development only
)

auth, err := session.NewAuth(store,
    session.WithTokenStore(tokenStore),
)

How it works:

  • On login: Session and user data are stored in a signed or encrypted cookie
  • On authentication: Data is read directly from the cookie
  • After stale duration: Falls back to session validation and refreshes the cache
  • Cookie must be signed or encrypted for security

Security note: When using trusted token stores, ensure the session's SecretHash field is never serialized to the client. Use the json:"-" tag to omit it from JSON encoding. The secret hash must remain in the database only

Custom TokenStore

Implement this interface for custom token storage (cookies, headers, etc.):

type TokenStore interface {
    // GetToken retrieves the session token from the request
    GetToken(r *http.Request) (sessionToken string, err error)

    // SetToken stores the session token in the response
    SetToken(w http.ResponseWriter, sessionToken string, expiresAt time.Time) error

    // DeleteToken removes the session token from the response
    DeleteToken(w http.ResponseWriter)
}

Example - Header-based token store

type HeaderTokenStore struct{}

func (s *HeaderTokenStore) GetToken(r *http.Request) (string, error) {
    token := r.Header.Get("Authorization")
    if token == "" {
        return "", http.ErrNoCookie // Use standard error
    }
    return strings.TrimPrefix(token, "Bearer "), nil
}

func (s *HeaderTokenStore) SetToken(w http.ResponseWriter, token string, expiresAt time.Time) error {
    w.Header().Set("X-Session-Token", token)
    return nil
}

func (s *HeaderTokenStore) DeleteToken(w http.ResponseWriter) {
    w.Header().Del("X-Session-Token")
}
Custom TrustedTokenStore

Implement this interface to add optimistic validation with session/user caching (like JWT, signed tokens, etc.):

type TrustedTokenStore[S Session, U any] interface {
    TokenStore // Embed TokenStore methods

    // FromTrustedToken validates and extracts session/user data from a trusted token
    // Return *StaleSessionError to fallback to session store validation
    FromTrustedToken(trustedToken string) (session S, user U, err error)

    // ToTrustedToken creates a trusted token containing session and user data
    // The returned token will be passed to TokenStore.SetToken()
    ToTrustedToken(sessionToken string, session S, user U) (trustedToken string, err error)
}

Example - JWT-based trusted token store:

type JWTTokenStore struct {
    signingKey []byte
}

func (s *JWTTokenStore) GetToken(r *http.Request) (string, error) {
    // Get JWT from Authorization header
    auth := r.Header.Get("Authorization")
    return strings.TrimPrefix(auth, "Bearer "), nil
}

func (s *JWTTokenStore) SetToken(w http.ResponseWriter, token string, expiresAt time.Time) error {
    // Return JWT in response header for client to store
    w.Header().Set("X-Session-Token", token)
    return nil
}

func (s *JWTTokenStore) DeleteToken(w http.ResponseWriter) {
    // Signal client to clear the token
    w.Header().Set("X-Session-Token", "")
}

func (s *JWTTokenStore) FromTrustedToken(token string) (Session, User, error) {
    // Parse and validate JWT signature
    claims, err := jwt.Parse(token, s.signingKey)
    if err != nil {
        return Session{}, User{}, err
    }

    // Check if JWT is expired - extract original session token for fallback session validation
    if time.Now().After(claims.ExpiresAt) {
        return Session{}, User{}, &session.StaleSessionError{
            SessionToken: claims.SessionToken,
        }
    }

    // Return cached session and user data
    return claims.Session, claims.User, nil
}

func (s *JWTTokenStore) ToTrustedToken(sessionToken string, sess Session, user User) (string, error) {
    // Create JWT with session and user data
    claims := JWTClaims{
        Session:                sess,
        User:                   user,
        OriginalSessionToken:   sessionToken,
        StaleAt:                time.Now().Add(15 * time.Minute),
    }
    return jwt.Sign(claims, s.signingKey)
}

Key points:

  • FromTrustedToken receives the token from GetToken()
  • Return *StaleSessionError to trigger session revalidation when cache expires
  • ToTrustedToken creates the trusted token that goes to SetToken()
  • The original session token should be embedded for fallback validation
Key Rotation

Support for rotating encryption/signing keys without invalidating existing sessions. Pass multiple secrets when creating token stores - the first key is used for new operations, older keys are tried for validation.

oldSecret := []byte("old-secret-key")
newSecret := []byte("new-secret-key")

// Use multiple secrets for key rotation
tokenStore, err := session.NewTrustedCookieTokenStore[Session, User](
    session.Secret(newSecret, oldSecret), // New key first, old keys follow
    time.Minute * 15,
    session.WithCookieName("auth_session"),
)

auth, err := session.NewAuth(store,
    session.WithTokenStore(tokenStore),
)

This allows seamless key rotation: new sessions use the new key, while existing sessions with the old key remain valid.

Cookies

Type-safe cookie operations with signing and encryption support. Uses generic types for automatic JSON serialization of your data structures.

Unsigned Cookies

Suitable for non-sensitive data like user preferences or UI settings. The data is stored as plain JSON and is readable by the client.

// Create cookie (unsigned by default)
cookie, err := session.NewCookie[UserData](session.CookieOptions{
    Name:   "user_prefs",
})

// Set cookie
userData := UserData{Theme: "dark", Lang: "en"}
cookie.Set(w, userData)

// Get cookie
data, err := cookie.Get(r)

// Delete cookie
cookie.Delete(w)
Signed Cookies

Prevents tampering using HMAC-SHA256 signatures. The data is still readable by the client, but any modifications will invalidate the signature. Use this for data that needs integrity protection but doesn't need to be hidden.

Supports key rotation by passing multiple secrets (the first key is used for signing, older keys are tried for verification).

secret := session.Secret([]byte("your-secret-key"))

// Create an signed cookie
cookie, err := session.NewCookie[SensitiveData](session.CookieOptions{
    Name:      "sensitive",
    Secret:    secret,
})
Encrypted Cookies

Encrypts data using AES-256-GCM, which both hides the content and prevents tampering. The data is completely hidden from the client. Use this for sensitive information that must remain confidential (e.g., tokens, personal data).

Supports key rotation by passing multiple secrets (the first key is used for encryption, older keys are tried for decryption).

secret := session.Secret([]byte("your-secret-key"))

// Create an encrypted cookie
cookie, err := session.NewCookie[SensitiveData](session.CookieOptions{
    Name:      "sensitive",
    Secret:    secret,
    Encrypted: true,
})
// Using DefaultCookieOptions with custom options
opts := session.DefaultCookieOptions("my_cookie",
    session.WithCookieSecret(session.Secret(key1, key2)),
    session.WithCookieDuration(time.Hour * 24),
    session.WithCookieSecure(true),
    session.WithCookieHttpOnly(true),
    session.WithCookieSameSite(http.SameSiteStrictMode),
    session.WithCookiePath("/"),
    session.WithCookieDomain("example.com"),
)
cookie, err := session.NewCookie[T](opts)

// Or using CookieOptions directly
cookie, err := session.NewCookie[T](session.CookieOptions{
    Name:     "my_cookie",
    Secret:   session.Secret(key1, key2),
    Duration: time.Hour * 24,
    Secure:   true,
    HttpOnly: true,
    SameSite: http.SameSiteStrictMode,
    Path:     "/",
    Domain:   "example.com",
})

Flash Messages

Temporary messages that are automatically deleted after being read once. Flash messages are stored as session cookies (expire when browser closes) by default and support all cookie features like signing and encryption.

// Create flash cookie
flash, err := session.NewFlashCookie[string](session.CookieOptions{
    Name:   "flash_message",
    Secret: session.Secret(key),
})

// Set flash message (on redirect)
flash.Set(w, "Account created successfully!")
http.Redirect(w, r, "/dashboard", http.StatusSeeOther)

// Get and delete flash message (on next request)
message, err := flash.Get(w, r)

// Or peek without deleting
message, err := flash.Peek(r)

Documentation

Overview

Package session implements session based authentication type-safe cookies, and flash messages.

Index

Constants

This section is empty.

Variables

View Source
var (
	// ErrExpiredSession is returned when a session is expired and has been successfully deleted.
	ErrExpiredSession = errors.New("expired session")

	// ErrInvalidSessionSecret is returned when a session secret does not match the stored secret.
	ErrInvalidSessionSecret = errors.New("invalid session secret")
)

Functions

func ParseSessionToken

func ParseSessionToken(sessionToken string) (sessionId string, sessionSecret string)

ParseSessionToken splits a session token into its session ID and secret components. Session tokens have the format: <session_id>.<session_secret>

func Secret

func Secret(b ...[]byte) [][]byte

Secret creates a slice of keys for signing and encrypting cookies. The first key is used for signing/encrypting new cookies. All keys are tried when verifying/decrypting existing cookies (for key rotation support).

Example usage:

Secret(key1)                    // Single key
Secret(key1, key2, key3)        // Key rotation (key1 is primary)

func WithCookieDomain

func WithCookieDomain(domain string) func(*CookieOptions)

WithCookieDomain sets the cookie domain. Default: "" (current domain only).

func WithCookieDuration

func WithCookieDuration(duration time.Duration) func(*CookieOptions)

WithCookieDuration sets the cookie duration. If > 0, creates a persistent cookie. If 0, creates a session cookie. Default: 0 (session cookie).

func WithCookieEncrypted

func WithCookieEncrypted(encrypted bool) func(*CookieOptions)

WithCookieEncrypted enables AES-256-GCM encryption for cookies. Requires a secret key of exactly 32 bytes. Default: false (not encrypted).

func WithCookieHttpOnly

func WithCookieHttpOnly(httpOnly bool) func(*CookieOptions)

WithCookieHttpOnly sets the HttpOnly flag on the cookie. When true, cookie is not accessible via JavaScript. Default: true (http only).

func WithCookieName

func WithCookieName(name string) func(*CookieOptions)

WithCookieName sets the cookie name.

func WithCookiePath

func WithCookiePath(path string) func(*CookieOptions)

WithCookiePath sets the cookie path. Default: "/" (all paths).

func WithCookieSameSite

func WithCookieSameSite(sameSite http.SameSite) func(*CookieOptions)

WithCookieSameSite sets the SameSite attribute on the cookie. Options: http.SameSiteDefaultMode, http.SameSiteLaxMode, http.SameSiteStrictMode, http.SameSiteNoneMode Default: http.SameSiteLaxMode

func WithCookieSecret

func WithCookieSecret(secret [][]byte) func(*CookieOptions)

WithCookieSecret sets the cookie secret for signing/encryption. Use Secret(key) for a single key or Secret(key1, key2, ...) for key rotation.

Cookie behavior based on Secret:

  • No Secret: Unsigned cookie (not recommended for sensitive data)
  • Secret provided: Signed cookie (HMAC-SHA256, prevents tampering)
  • Secret + WithEncrypted(true): Encrypted cookie (AES-256-GCM, hides data)

func WithCookieSecure

func WithCookieSecure(secure bool) func(*CookieOptions)

WithCookieSecure sets the Secure flag on the cookie. When true, cookie is only sent over HTTPS. Default: true (secure).

func WithDev

func WithDev(isDev bool) func(*AuthOptions)

WithDev enables development mode. In dev mode, Secure flag is disabled for cookies.

func WithDuration

func WithDuration(duration time.Duration) func(*AuthOptions)

WithDuration sets the session duration. Default: 30 days if not specified.

func WithGenerateSessionToken

func WithGenerateSessionToken(fn func() (sessionId, sessionSecret string, err error)) func(*AuthOptions)

WithGenerateSessionToken sets the session token generator function. Default: base32 encoding (lowercase, no padding) of 20 random bytes for session id and secret.

func WithRefreshThreshold

func WithRefreshThreshold(fn func(expiresAt time.Time, duration time.Duration) (newExpiresAt time.Time, shouldRefresh bool)) func(*AuthOptions)

WithRefreshThreshold sets the session refresh threshold function. Set to nil to disable automatic session refresh. Default: half-time refresh threshold.

func WithTokenStore

func WithTokenStore(store TokenStore) func(*AuthOptions)

WithTokenStore sets the token store. TokenStore may implement TrustedTokenStore.

Types

type Auth

type Auth[S Session, U any] interface {

	// CreateSession creates a new session for the given user.
	// Returns the session token (<session id>.<session secret>) and the created session.
	CreateSession(user U) (sessionToken string, session S, err error)

	// InvalidateSession deletes a session by its ID.
	InvalidateSession(sessionId string) error

	// InvalidateSession deletes all sessions for user.
	InvalidateAllSessions(user U) error

	// GetSessionToken retrieves the session token from the request.
	GetSessionToken(r *http.Request) (sessionToken string, err error)

	// SetSessionToken stores the session token in the response.
	// Uses TrustedTokenStore if available, otherwise uses regular TokenStore.
	SetSessionToken(w http.ResponseWriter, sessionToken string, session S, user U) error

	// DeleteSessionToken removes the session token from the response.
	DeleteSessionToken(w http.ResponseWriter)

	// ValidateSessionToken validates a session token and returns session data.
	// Automatically refreshes sessions that are past their refresh threshold.
	// Returns optimistic=true if a trusted token store was used and the session token
	// was validated without checking the session store.
	// The token store should always be updated with the returned session if optimistic=false.
	ValidateSessionToken(sessionToken string) (session S, user U, optimistic bool, err error)

	// LoginRequest creates a new session and sets the session token in the response.
	// Use this after successful user login or registration.
	LoginRequest(w http.ResponseWriter, user U) (session S, err error)

	// AuthenticateRequest validates the session token from the request and returns session data.
	// Automatically refreshes sessions that are past their refresh threshold.
	// Updates the token store automatically with the returned session when optimistic=false.
	AuthenticateRequest(w http.ResponseWriter, r *http.Request) (session S, user U, err error)

	// LogoutRequest validates the request, invalidates the session, and deletes the session token.
	// Use this for logout operations.
	LogoutRequest(w http.ResponseWriter, r *http.Request) (session S, user U, err error)
}

Auth provides user authentication and session management operations.

Example usage:

// Create auth instance
auth, _ := NewAuth(sessionStore)

// Login user
session, _ := auth.LoginRequest(w, user)

// Authenticate user on protected routes
session, user, _ := auth.AuthenticateRequest(w, r)

// Logout user
session, user, _ := auth.LogoutRequest(w, r)

func NewAuth

func NewAuth[S Session, U any](sessionStore SessionStore[S, U], opts ...func(*AuthOptions)) (Auth[S, U], error)

NewAuth creates a new Auth instance with the given session store and options.

Defaults:

  • IsDev: false
  • Duration: 30 days
  • TokenStore: Unsigned cookie token store (stores session ID)
  • RefreshThreshold: Half-time (refresh when 50% of duration has passed)
  • GenerateSessionToken: Base32 encoding of 20 random bytes

Example:

auth, err := NewAuth(sessionStore,
    WithDev(true),
    WithDuration(time.Hour * 24 * 7),
    WithTokenStore(customTokenStore),
)

type AuthOptions

type AuthOptions struct {
	IsDev bool

	// Duration configures the session duration. default is 30 days.
	Duration time.Duration

	// TokenStore configures the token store.
	// TokenStore may implement [TrustedTokenStore].
	TokenStore TokenStore

	// RefreshThreshold configures how often a session is refreshed. default is half-time refresh threshold.
	// Set to nil to disabled refresh.
	RefreshThreshold func(expiresAt time.Time, duration time.Duration) (newExpiresAt time.Time, shouldRefresh bool)

	// GenerateSessionToken configures the session token generator function.
	// default is base32 encoding (lowercase, no padding) of 20 random bytes for session id and secret.
	GenerateSessionToken func() (sessionId, sessionSecret string, err error)
}
type Cookie[T any] interface {
	// Get reads and parses a cookie value from an HTTP request.
	// Returns an error if the cookie is not found, malformed, or has an invalid signature.
	Get(r *http.Request) (T, error)

	// Set creates a cookie with the given data and writes it to the HTTP response.
	// Optional cookie modifier functions can be passed to override defaults.
	Set(w http.ResponseWriter, data T, options ...func(*http.Cookie)) error

	// Delete removes the cookie from the HTTP response by setting MaxAge to -1.
	Delete(w http.ResponseWriter)
}

Cookie provides high-level cookie operations for HTTP request/response handling. This is the primary interface for typical cookie usage - reading from requests and writing to responses directly.

func FromRawCookie

func FromRawCookie[T any](raw RawCookie[T]) Cookie[T]

func NewCookie

func NewCookie[T any](options CookieOptions) (Cookie[T], error)

NewCookie creates a new cookie instance that provides high-level cookie operations for HTTP request/response handling.

The generic type T is JSON-marshaled and optionally signed (HMAC-SHA256) and/or encrypted (AES-256-GCM).

Options:

  • Name: Cookie name (required)
  • Duration: If > 0, persistent cookie. Default: 0 (session cookie, expires when browser closes).
  • Secure: Only send over HTTPS. Default: false
  • HttpOnly: Block JavaScript access. Default: false
  • SameSite: Lax/Strict/None mode. Default: 0 (browser default, typically Lax)

Cryptographic security:

  • Signing: Prevents tampering. Default: enabled. Disable with Unsigned=true.
  • Encryption: Hides data from clients. Default: disabled. Enable with Encrypted=true.
  • Secret: Required if signed or encrypted. Use Secret(key) for a single key or Secret(key1, key2, ...) for key rotation.

Example usage:

// Using DefaultCookieOptions for secure defaults
opts := DefaultCookieOptions("user_session",
    WithCookieSecret(Secret(key)),
    WithCookieSecure(false), // For development
)
cookie, _ := NewCookie[UserData](opts)

// Or using CookieOptions directly
cookie, _ := NewCookie[UserData](CookieOptions{
    Name:   "user_session",
    Secret: Secret(key),
})

type CookieOptions

type CookieOptions struct {
	// Secret is a slice of keys for signing and encrypting cookies.
	// Use Secret(key) for a single key or Secret(key1, key2, ...) for key rotation.
	// The first key is used for signing/encrypting, all keys are tried for verification/decryption.
	//
	// Cookie security based on Secret:
	//   - No Secret (nil or empty): Unsigned cookie
	//   - Secret provided: Signed cookie (HMAC-SHA256)
	//   - Secret + Encrypted=true: Encrypted cookie (AES-256-GCM)
	Secret [][]byte

	// Encrypted enables AES-256-GCM encryption.
	// Requires Secret to be set with keys of exactly 32 bytes each.
	Encrypted bool

	// Name configures the cookie name.
	Name string

	// Duration configures the session duration.
	// This is used to set the Expires time when a cookie is set.
	Duration time.Duration

	Path     string
	Domain   string
	Secure   bool
	HttpOnly bool
	SameSite http.SameSite
}

func DefaultCookieOptions

func DefaultCookieOptions(name string, opts ...func(*CookieOptions)) CookieOptions

DefaultCookieOptions creates a CookieOptions with secure defaults. The name parameter is required. Additional options can be provided to override defaults.

Default values:

  • Secure: true
  • HttpOnly: true
  • SameSite: Lax mode
  • Path: "/"

Cookie signing/encryption:

  • No Secret: Unsigned cookie (not recommended for sensitive data)
  • Secret provided: Signed cookie (HMAC-SHA256, prevents tampering)
  • Secret + Encrypted=true: Encrypted cookie (AES-256-GCM, hides data)

Example usage:

// Basic unsigned cookie
opts := DefaultCookieOptions("session_id")

// Signed cookie
opts := DefaultCookieOptions("session_id",
    WithCookieSecret(Secret(key)),
)

// Encrypted cookie
opts := DefaultCookieOptions("session_id",
    WithCookieSecret(Secret(key)),
    WithEncrypted(true),
)

type FlashCookie

type FlashCookie[T any] interface {
	// Peek reads the flash message without deleting it.
	// Returns an error if the cookie is not found, malformed, or has an invalid signature.
	Peek(r *http.Request) (T, error)

	// Get reads the flash message and immediately deletes it from the response.
	// Returns an error if the cookie is not found, malformed, or has an invalid signature.
	Get(w http.ResponseWriter, r *http.Request) (T, error)

	// Set writes a flash message to the response cookies.
	// Optional cookie modifier functions can be passed to override defaults.
	Set(w http.ResponseWriter, data T, options ...func(*http.Cookie)) error
}

FlashCookie provides flash message functionality using cookies. Flash cookies are deleted immediately after being read once. By default, they are session cookies that expire when the browser closes.

Example usage:

flash, _ := NewFlashCookie[string](FlashCookieOptions{
    Name: "flash_message",
    Secret: Secret(key),
})

// Set a flash message
flash.Set(w, "Account created successfully!")

// Read and delete in one operation
message, _ := flash.Get(w, r)

// Peek without deleting
message, _ := flash.Peek(r)

func NewFlashCookie

func NewFlashCookie[T any](options CookieOptions) (FlashCookie[T], error)

NewFlashCookie creates a new flash cookie. Flash cookies are deleted immediately after being read once.

The Duration field in CookieOptions is ignored for flash cookies. By default, flash cookies are session cookies (expire when browser closes).

type RawCookie

type RawCookie[T any] interface {
	// Name returns the configured cookie name.
	Name() string

	// Data encodes cookie data into a raw cookie value string.
	Data(data T) (string, error)

	// Parse decodes and validates a raw cookie value string.
	Parse(value string) (T, error)

	// SetCookie returns an http.Cookie with the given value.
	SetCookie(value string, options ...func(*http.Cookie)) *http.Cookie

	// RemoveCookie creates an http.Cookie configured to delete itself by setting MaxAge to -1.
	RemoveCookie() *http.Cookie
}

RawCookie provides low-level cookie operations for working with cookie values. Use this interface when you need manual control over cookie creation and parsing.

Example usage:

cookie, _ := NewRawCookie[UserSession](CookieOptions{...})

// Get cookie name
name := cookie.Name()

// Encode data to cookie value
sessionData := SessionData{...}
value, _ := cookie.Data(sessionData)

// Parse raw cookie value
parsed, _ := cookie.Parse(value)

// Create cookie object with value
httpCookie := cookie.SetCookie(value)

// Create removal cookie
removeCookie := cookie.RemoveCookie()

func NewRawCookie

func NewRawCookie[T any](options CookieOptions) (RawCookie[T], error)

NewCooNewRawCookiekie creates a new raw cookie instance that provides low-level cookie operations for working with cookie values.

The generic type T is JSON-marshaled and optionally signed (HMAC-SHA256) and/or encrypted (AES-256-GCM).

Options:

  • Name: Cookie name (required)
  • Duration: If > 0, persistent cookie. Default: 0 (session cookie, expires when browser closes).
  • Secure: Only send over HTTPS. Default: false
  • HttpOnly: Block JavaScript access. Default: false
  • SameSite: Lax/Strict/None mode. Default: 0 (browser default, typically Lax)

Cryptographic security:

  • Signing: Prevents tampering. Default: enabled. Disable with Unsigned=true.
  • Encryption: Hides data from clients. Default: disabled. Enable with Encrypted=true.
  • Secret: Required if signed or encrypted. Use Secret(key) for a single key or Secret(key1, key2, ...) for key rotation.

type Session

type Session interface {
	GetSession() (sessionId string, sessionSecretHash []byte, expiresAt time.Time)
}

Session represents a user session with an ID, secret hash and expiration time.

The secret hash must not be exposed. If the session type is returned to the client, ensure that the secret hash field is always omitted.

type SessionStore

type SessionStore[S Session, U any] interface {
	// GetSessionAndUser retrieves a session and its associated user by session ID.
	GetSessionAndUser(sessionId string) (S, U, error)

	// CreateSession creates a new session for a user with the given session data.
	CreateSession(sessionData Session, user U) (S, error)

	// UpdateSession updates a session's expiration time (used for session refresh).
	UpdateSession(sessionId string, expiresAt time.Time) (S, error)

	// DeleteSession deletes a session by ID.
	DeleteSession(sessionId string) error

	// DeleteUserSessions deletes all sessions for user.
	DeleteUserSessions(user U) error
}

SessionStore provides storage operations for sessions and users.

type StaleSessionError

type StaleSessionError struct{ SessionToken string }

StaleSessionError indicates that the trusted token is stale and requires fallback to session store validation.

func (*StaleSessionError) Error

func (e *StaleSessionError) Error() string

type TokenStore

type TokenStore interface {
	// GetToken retrieves the session token from the request.
	GetToken(r *http.Request) (sessionToken string, err error)

	// SetToken stores the session token in the response.
	SetToken(w http.ResponseWriter, sessionToken string, expiresAt time.Time) error

	// DeleteToken removes the session token from the response.
	DeleteToken(w http.ResponseWriter)
}

TokenStore provides token storage operations for HTTP requests/responses. Default implementation uses unsigned cookies.

func NewCookieTokenStore

func NewCookieTokenStore(opts ...func(*CookieOptions)) (TokenStore, error)

NewCookieTokenStore creates a basic cookie-based token store that stores session tokens. The cookie is unsigned by default (just stores the session ID).

Default options:

  • Name: "auth_session"
  • Secure: true
  • HttpOnly: true
  • SameSite: Lax mode
  • Path: "/"

Example usage:

// With default options
tokenStore, _ := NewCookieTokenStore()

// With custom options
tokenStore, _ := NewCookieTokenStore(
    WithCookieName("my_session"),
    WithCookieSecure(false), // For development
)

type TrustedTokenStore

type TrustedTokenStore[S Session, U any] interface {
	TokenStore

	// FromTrustedToken attempts to validate and extract session data from a token.
	// The sessionToken parameter comes from TokenStore.GetToken().
	// Returns a *StaleSessionError to fallback to validating the session token with the session store.
	FromTrustedToken(trustedToken string) (session S, user U, err error)

	// ToTrustedToken transforms session data into a trusted token string.
	// The returned token will be passed to TokenStore.SetToken().
	ToTrustedToken(sessionToken string, session S, user U) (trustedToken string, err error)
}

TrustedTokenStore validates session data optimistically to avoid checking the session store. Use this for short-lived signed cookies or JWT tokens.

func NewTrustedCookieTokenStore

func NewTrustedCookieTokenStore[S Session, U any](secret [][]byte, staleDuration time.Duration, opts ...func(*CookieOptions)) (TrustedTokenStore[S, U], error)

NewTrustedCookieTokenStore creates a cookie-based token store with session/user caching. This implements TrustedTokenStore to avoid session validation until the cache becomes stale.

The cookie MUST be signed or encrypted for security (default is signed). Session and user data are stored in the cookie and trusted for the stale duration. After the stale duration elapses, the system falls back to session store validation using the stored session token.

Default options:

  • Secret: secret
  • Name: "auth_session"
  • Secure: true
  • HttpOnly: true
  • SameSite: Lax mode
  • Path: "/"

Example usage:

// With encrypted cookies
tokenStore, _ := NewTrustedCookieTokenStore[MySession, MyUser](
    Secret(secret),
    time.Minute * 15, // Trust for 15 minutes before session store check
    WithCookieEncrypted(true),
    WithCookieName("my_session"),
    WithCookieSecure(false), // For development
)

Jump to

Keyboard shortcuts

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