ESC
Type to search...
S
Soli Docs

Session Functions

Server-side session management with pluggable storage backends.

Storage Backends

Soli supports multiple session storage backends. Configure via code, environment variables, or config files.

Driver Description Configuration
in_memory Default. Fast but lost on restart None
disk File-based JSON storage path: directory (default: ./sessions)
solidb SolidB HTTP database solidb_host, solidb_database, solidb_collection
solikv SoliKV/Redis with TTL solikv_host, solikv_port, solikv_token
cookie Encrypted client-side sessions (AES-256-GCM) — the payload travels in the cookie. Survives restarts, works across hosts, ~4KB limit, no server-side revocation secret: 32+ chars (or SOLI_SESSION_SECRET)

Configuration

session_configure(options)

Configure session storage at runtime. Supports driver, path, secret, solidb_*, and solikv_* options.

Examples

session_configure({"driver": "disk", "path": "./sessions"})
session_configure({"driver": "solidb", "solidb_host": "localhost:8080", "solidb_database": "myapp"})
session_configure({"driver": "solikv", "solikv_host": "localhost", "solikv_port": 6380})
session_configure({"driver": "cookie", "secret": getenv("SOLI_SESSION_SECRET")})
session_driver()

Get the current session storage driver name.

Returns

String - One of: "in_memory", "disk", "solidb", "solikv", "cookie"
current = session_driver()
print("Using: " + current)
session_config()

Get the current session configuration as a Hash.

Returns

Hash - Configuration with driver, path, host, port, ttl, etc.
config = session_config()
print(config["driver"])
print(config["ttl"])

Readiness & Zero-Downtime Deploys

With a network-backed driver (solidb or solikv), a freshly-booted process must open its first connection to the session store before it can serve a session-backed request. Soli warms that connection at boot (retrying with backoff until the store is reachable) and exposes a built-in readiness endpoint so load balancers don't route traffic to an instance that can't yet serve:

Endpoint Behavior
GET /up Returns 503 warming until the session-store connection is warmed, then 200 ready. Ready immediately for in-memory/disk/cookie drivers.

Point your load balancer's health check at /up. Under soli-proxy, auto-detected Soli apps already use /up as the blue/green promotion gate — the old slot keeps serving until the new slot reports ready, closing the post-deploy window where the first requests would otherwise stall on a cold session connection. /up is a built-in route; defining your own has no effect.

Environment Variables

Session configuration can also be set via environment variables:

Variable Description Default
SOLI_SESSION_DRIVER Storage backend in_memory
SOLI_SESSION_SECRET Secret for the cookie driver (32+ chars). Rotating it invalidates all sessions unset
SOLI_SESSION_PATH Path for disk storage ./sessions
SOLI_SOLIDB_HOST SolidB server address localhost:8080
SOLI_SOLIDB_DATABASE SolidB database name solidb
SOLI_SOLIKV_HOST SoliKV server address localhost
SOLI_SOLIKV_PORT SoliKV port 6380
SOLI_SESSION_TTL Session timeout (seconds) 86400

Cookies

Cookies from the Cookie header are automatically parsed and exposed as the global cookies hash. Defaults to {} when no cookies are present. Available in controllers, middleware, and views.

cookies

Global hash of parsed cookies from the Cookie header.

# Read a cookie
theme = cookies["theme"] or "light"
session_id = cookies.session_id
Signed & encrypted cookies

{"signed": true} seals the value with HMAC-SHA256 (readable on the client as base64url JSON, but tamper-proof); {"encrypted": true} seals it with AES-256-GCM (opaque). Sealed values accept any JSON-serializable value, not just strings. Both keys are HKDF-derived from SOLI_SESSION_SECRET (32+ chars; sealing raises without it), the cookie name is bound into the seal so values can't be swapped between cookies, and a max_age is embedded as an expiry inside the payload. The two options are mutually exclusive.

set_cookie("prefs", {"theme": "dark"}, {"encrypted": true, "max_age": 86400})
set_cookie("uid", 42, {"signed": true})
csrf_token()

The per-session CSRF token (32 hex chars), created on first use. Views rarely call it directly — form_with(...).open(), button_to, and csrf_field() embed it as a hidden _csrf_token input, and csrf_meta_tag() exposes it for JS clients sending X-CSRF-Token. The server verifies supplied tokens against the session (constant-time) and rejects mismatches with 403. See Forms & CSRF.

# In a layout, for fetch/htmx clients:
# <body hx-headers='{"X-CSRF-Token": "<%= csrf_token() %>"}'>
token = csrf_token()

Common Patterns

Authentication Flow

# Login
def login(email: String, password: String) -> Bool
  user = User.find_by_email(email)
  if !user || !argon2_verify(password, user["password_hash"])
    return false
  end

  session_set("user_id", user["id"])
  session_regenerate  # Prevent session fixation
  true
end

# Check authentication
def current_user -> Hash?
  user_id = session_get("user_id")
  if !user_id
    return null
  end
  User.find(user_id)
end

# Logout
def logout
  session_destroy
end

Flash Messages

# Set a flash message
def flash(type: String, message: String)
  flashes = session_get("_flashes") ?? []
  push(flashes, { "type": type, "message": message })
  session_set("_flashes", flashes)
end

# Get and clear flash messages
def get_flashes -> Array
  flashes = session_get("_flashes") ?? []
  session_delete("_flashes")
  flashes
end

# Usage
flash("success", "Account created!")
flash("error", "Invalid email address")