Help us shape the future of Go! Take the 2026 Go Developer Survey

session

package
v0.6.0 Latest Latest
Warning

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

Go to latest
Published: Oct 25, 2026 License: MIT Imports: 11 Imported by: 2

Documentation

Overview

Package session provides a session storage interface with controls.

Session storage extends key-value storage with session-specific operations:

  • User-based session lookups and deletion
  • Automatic TTL management
  • Size limits and validation
  • Touch/heartbeat operations

Available Backends

  • memory: In-memory storage (for development/testing)
  • kvs: Adapts any kvs.ListableStore (Redis, SQLite, etc.)

Index

Constants

View Source
const (
	// ErrCodeInvalidSession indicates the session is malformed or missing required fields.
	ErrCodeInvalidSession = "SESSION_INVALID"

	// ErrCodeSizeLimitExceeded indicates the session data exceeds the configured limit.
	ErrCodeSizeLimitExceeded = "SESSION_SIZE_EXCEEDED"

	// ErrCodeNotSerializable indicates session data cannot be serialized to JSON.
	ErrCodeNotSerializable = "SESSION_NOT_SERIALIZABLE"

	// ErrCodeNotFound indicates the session does not exist.
	ErrCodeNotFound = "SESSION_NOT_FOUND"

	// ErrCodeExpired indicates the session has expired.
	ErrCodeExpired = "SESSION_EXPIRED"

	// ErrCodeStoreClosed indicates the store has been closed.
	ErrCodeStoreClosed = "STORE_CLOSED"

	// ErrCodeSessionLimitExceeded indicates the user has too many concurrent sessions.
	ErrCodeSessionLimitExceeded = "SESSION_LIMIT_EXCEEDED"

	// ErrCodeSiteMismatch indicates the session belongs to a different site.
	ErrCodeSiteMismatch = "SESSION_SITE_MISMATCH"
)

Error codes for session operations. These can be used by HTTP handlers to return appropriate status codes.

View Source
const MaxSessionIDLength = 256

MaxSessionIDLength is the longest session ID ValidSessionID accepts.

View Source
const SessionIDLength = 32

SessionIDLength is the length of generated session IDs in bytes.

Variables

View Source
var (
	ErrNotFound             = errors.New("session not found")
	ErrExpired              = errors.New("session expired")
	ErrInvalidSession       = errors.New("invalid session")
	ErrSizeLimitExceeded    = errors.New("session size limit exceeded")
	ErrSessionLimitExceeded = errors.New("session limit exceeded")
	ErrSiteMismatch         = errors.New("session belongs to different site")
	ErrClosed               = errors.New("store is closed")
)

Common errors.

Functions

func ErrorCode

func ErrorCode(err error) string

ErrorCode extracts the error code from an error, if it's a SessionError. Returns empty string for non-SessionError errors.

func ErrorDetails

func ErrorDetails(err error) map[string]any

ErrorDetails extracts details from an error, if it's a SessionError.

func GenerateSessionID

func GenerateSessionID() (string, error)

GenerateSessionID generates a cryptographically secure session ID.

func SessionRef added in v0.6.0

func SessionRef(id string) string

SessionRef returns a short, non-reversible reference to a session ID for logs, errors and violation events: the first 8 hex characters of the SHA-256 of the ID. Session IDs are bearer credentials and must not be logged in full; the reference lets log lines about the same session be correlated without exposing it. SessionRef returns "" for an empty ID.

func ValidSessionID added in v0.6.0

func ValidSessionID(id string) bool

ValidSessionID reports whether id is a well-formed session ID: 1 to MaxSessionIDLength characters from the URL-safe set A-Z, a-z, 0-9, '-', '_' and '.', which covers GenerateSessionID. Session IDs come from client cookies, so stores must refuse others: a backend that keeps sessions and its own index records in one key space (such as the kvs backend's "user:" index keys) would otherwise let a crafted ID address an index.

Types

type Config

type Config struct {
	// SiteID identifies which site/service this store handles.
	// Used for multi-site isolation (e.g., "academyos", "agentos", "dashforge").
	// When set, all sessions are tagged with this SiteID and Get operations
	// validate the session belongs to this site.
	// Required for ControlledStore when running multiple sites.
	SiteID string

	// MaxSessionSize is the maximum serialized session size in bytes.
	// Set to 0 for no limit.
	MaxSessionSize int

	// MaxSessionsPerUser limits concurrent sessions per user.
	// When exceeded, oldest sessions are deleted to make room.
	// Set to 0 for no limit.
	MaxSessionsPerUser int

	// DefaultTTL is the default session TTL if not specified.
	DefaultTTL time.Duration

	// CleanupInterval is how often to run automatic cleanup.
	// Set to 0 to disable automatic cleanup.
	CleanupInterval time.Duration

	// KeyPrefix is the prefix for session keys (for KVS backends).
	KeyPrefix string
}

Config contains configuration for session stores.

func DefaultConfig

func DefaultConfig() Config

DefaultConfig returns sensible default configuration.

type ControlOption

type ControlOption func(*ControlledStore)

ControlOption configures a ControlledStore.

func WithLogger

func WithLogger(logger *slog.Logger) ControlOption

WithLogger sets the logger for the controlled store.

func WithViolationHandler

func WithViolationHandler(handler ViolationHandler) ControlOption

WithViolationHandler sets a callback for policy violations. Use this to emit metrics (e.g., OTel counters) or alerts.

type ControlledStore

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

ControlledStore wraps a Store with size limits, validation, and observability.

func WithControls

func WithControls(store Store, cfg Config, opts ...ControlOption) *ControlledStore

WithControls wraps a Store with size limits and validation controls.

func (*ControlledStore) Close

func (s *ControlledStore) Close() error

Close closes the store.

func (*ControlledStore) Create

func (s *ControlledStore) Create(ctx context.Context, session *Session) error

Create stores a new session with validation.

func (*ControlledStore) Delete

func (s *ControlledStore) Delete(ctx context.Context, id string) error

Delete removes a session by ID. If SiteID is configured, a session that belongs to another site is left in place and, like a missing session, Delete returns nil.

func (*ControlledStore) DeleteByUserID

func (s *ControlledStore) DeleteByUserID(ctx context.Context, userID string) (int, error)

DeleteByUserID removes all sessions for a user. If SiteID is configured, only the user's sessions for this site are removed; sessions of other sites sharing the backend are left in place. That requires the underlying store to implement SessionLister; if it does not, DeleteByUserID returns an error and deletes nothing.

func (*ControlledStore) Get

func (s *ControlledStore) Get(ctx context.Context, id string) (*Session, error)

Get retrieves a session by ID. If SiteID is configured, validates the session belongs to this site.

func (*ControlledStore) ListByUserID

func (s *ControlledStore) ListByUserID(ctx context.Context, userID string) ([]*Session, error)

ListByUserID returns all sessions for a user if the underlying store supports it. If SiteID is configured, only returns sessions for this site. This implements SessionLister for transparent pass-through.

func (*ControlledStore) Touch

func (s *ControlledStore) Touch(ctx context.Context, id string) error

Touch updates the LastAccessedAt timestamp. If SiteID is configured, a session that belongs to another site returns ErrNotFound.

func (*ControlledStore) Unwrap

func (s *ControlledStore) Unwrap() Store

Unwrap returns the underlying store.

func (*ControlledStore) Update

func (s *ControlledStore) Update(ctx context.Context, session *Session) error

Update updates an existing session with validation. If SiteID is configured, the stored session must belong to this site (otherwise ErrNotFound is returned), and the updated session is stamped with the configured SiteID so the site binding survives the write.

type Session

type Session struct {
	// ID is the unique session identifier.
	ID string `json:"id"`

	// UserID is the authenticated user's ID.
	UserID uuid.UUID `json:"user_id"`

	// SiteID identifies which site/service this session belongs to.
	// Used for multi-site isolation (e.g., "academyos", "agentos", "dashforge").
	// Set automatically by ControlledStore based on Config.SiteID.
	SiteID string `json:"site_id,omitempty"`

	// OrganizationID is the current organization context (optional).
	OrganizationID *uuid.UUID `json:"organization_id,omitempty"`

	// Data contains arbitrary session data.
	// This can include tokens, preferences, etc.
	Data map[string]any `json:"data,omitempty"`

	// CreatedAt is when the session was created.
	CreatedAt time.Time `json:"created_at"`

	// UpdatedAt is when the session was last updated.
	UpdatedAt time.Time `json:"updated_at"`

	// LastAccessedAt is when the session was last accessed.
	LastAccessedAt time.Time `json:"last_accessed_at"`

	// ExpiresAt is when the session expires.
	ExpiresAt time.Time `json:"expires_at"`

	// IPAddress is the IP address that created the session.
	IPAddress string `json:"ip_address,omitempty"`

	// UserAgent is the user agent that created the session.
	UserAgent string `json:"user_agent,omitempty"`
}

Session represents a server-side session.

func NewSession

func NewSession(userID uuid.UUID, ttl time.Duration) (*Session, error)

NewSession creates a new session with the given parameters.

func (*Session) IsExpired

func (s *Session) IsExpired() bool

IsExpired returns true if the session has expired.

func (*Session) TTL

func (s *Session) TTL() time.Duration

TTL returns the remaining time until expiration.

type SessionError

type SessionError struct {
	// Code is a machine-readable error code.
	Code string

	// Message is a human-readable error message.
	Message string

	// Details contains additional error context.
	Details map[string]any

	// Cause is the underlying error, if any.
	Cause error
}

SessionError is a structured error with a code for programmatic handling.

func NewSessionError

func NewSessionError(code, message string, details map[string]any, cause error) *SessionError

NewSessionError creates a new SessionError.

func (*SessionError) Error

func (e *SessionError) Error() string

func (*SessionError) Is

func (e *SessionError) Is(target error) bool

Is implements errors.Is for SessionError.

func (*SessionError) Unwrap

func (e *SessionError) Unwrap() error

type SessionLister

type SessionLister interface {
	// ListByUserID returns all sessions for a user, sorted by CreatedAt ascending (oldest first).
	ListByUserID(ctx context.Context, userID string) ([]*Session, error)
}

SessionLister is an optional interface for stores that support listing sessions. Stores implementing this interface can enforce MaxSessionsPerUser.

type Store

type Store interface {
	// Create stores a new session.
	Create(ctx context.Context, session *Session) error

	// Get retrieves a session by ID.
	// Returns ErrNotFound if the session doesn't exist.
	// Returns ErrExpired if the session has expired.
	Get(ctx context.Context, id string) (*Session, error)

	// Update updates an existing session.
	// Returns ErrNotFound if the session doesn't exist.
	Update(ctx context.Context, session *Session) error

	// Delete removes a session by ID.
	Delete(ctx context.Context, id string) error

	// DeleteByUserID removes all sessions for a user.
	// Returns the number of sessions deleted.
	DeleteByUserID(ctx context.Context, userID string) (int, error)

	// Touch updates the LastAccessedAt timestamp.
	// This is used to track session activity without modifying other fields.
	Touch(ctx context.Context, id string) error

	// Close closes the store and releases any resources.
	Close() error
}

Store defines the interface for session storage. Implementations must be safe for concurrent use.

type ViolationEvent

type ViolationEvent struct {
	Type ViolationType
	// SessionID is no longer set, because session IDs are bearer
	// credentials and must not reach logs or metrics.
	//
	// Deprecated: Use SessionRef.
	SessionID string
	// SessionRef is SessionRef(id) of the session involved, a
	// non-reversible reference safe to log.
	SessionRef string
	UserID     uuid.UUID
	SiteID     string // Site identifier for multi-site isolation
	Size       int    // Current size in bytes
	Limit      int    // Configured limit
	Message    string
}

ViolationEvent contains information about a policy violation.

type ViolationHandler

type ViolationHandler func(ctx context.Context, event ViolationEvent)

ViolationHandler is called when a session policy is violated. Use this to emit metrics, alerts, or audit logs.

type ViolationType

type ViolationType string

ViolationType identifies the type of policy violation.

const (
	ViolationSizeExceeded         ViolationType = "size_exceeded"
	ViolationNotSerializable      ViolationType = "not_serializable"
	ViolationInvalidSession       ViolationType = "invalid_session"
	ViolationSessionLimitExceeded ViolationType = "session_limit_exceeded"
	ViolationSiteMismatch         ViolationType = "site_mismatch"
)

Directories

Path Synopsis
backend
kvs
Package kvs provides a session storage backend using kvs.ListableStore.
Package kvs provides a session storage backend using kvs.ListableStore.
memory
Package memory provides an in-memory session storage backend.
Package memory provides an in-memory session storage backend.

Jump to

Keyboard shortcuts

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