Skip to main content

Module session

Module session 

Source
Expand description

Cookie-based sessions over tower-sessions (a real, maintained session engine - the cookie carries only an opaque session ID, actual data lives server-side in a Store, which is the standard, more secure pattern rather than shipping session contents in the cookie itself).

Two real backends, chosen by Config::session_driver (SESSION_DRIVER - "database", the default, or "file"), both wrapped in one SessionBackend enum so session_layer always returns the same concrete SessionManagerLayer<SessionBackend> type regardless of which one is active:

  • AnySessionStore: a small hand-written tower_sessions:: SessionStore implementation over sqlx::AnyPool - not a third-party per-backend store crate (tower-sessions-sqlx-store, say). That crate’s SqliteStore/MySqlStore each need their own concretely- typed SqlitePool/MySqlPool, but larust_orm::pool() hands out a runtime-generic AnyPool (see larust_orm::Backend) with no way to recover a concrete pool from it - so a store built directly against AnyPool, branching its own SQL by larust_orm::backend the same way every other framework crate with its own table does (larust-permissions, larust-queue, …), is both the only real option and the one consistent with how the rest of this framework already handles the two backends.
  • FileSessionStore: one file per session under storage/sessions/ - Laravel’s own SESSION_DRIVER=file equivalent, for an app that would rather not put session churn through its own database at all (especially now that docs/GOTCHAS.md documents a real production incident SQLite-backed sessions caused under write-heavy load). Only works for a single server - every process sharing this store needs to see the same directory, which a real multi-server deployment behind a load balancer can’t guarantee the way a shared database can.

Neither is an in-memory store: session data needs to survive a process restart (a deploy, a crash, xr dev’s rebuild-and-restart cycle), not just live for the lifetime of one process. There’s deliberately no in-memory option in this crate’s public API at all: an in-memory store is a real, common trap (an app that “works” in every manual test, then silently logs everyone out on every deploy) - same shape as Laravel’s own array session driver being the wrong thing to ship to production. "file" doesn’t have that problem - real files on disk survive a restart/crash exactly the way a database row does - which is why it’s offered even though array deliberately isn’t.

Structs§

AnySessionStore
A tower_sessions::SessionStore over sqlx::AnyPool - see this module’s own doc comment for why this is hand-written rather than a third-party store crate. The session’s own Record (id/data/expiry) is stored as one row: data as a JSON-serialized TEXT column (serde_json is already a workspace-wide dependency; no need for a binary encoding crate just for this), expiry_date as Unix-epoch seconds - the same “epoch seconds as INTEGER” convention every other framework-owned table in this codebase already uses (larust-cache’s cache_items, larust-queue’s jobs, larust-notifications’s notifications), not tower-sessions-sqlx-store’s own native-timestamp-column choice.
FileSessionStore
A tower_sessions::SessionStore backed by plain files on disk, one per session - see this module’s own doc comment for when this is used instead of AnySessionStore. Each session’s Record is JSON-encoded (the same [encode]/[decode] helpers AnySessionStore itself uses) into a file named after Id’s own rendering.
Session
A session which allows HTTP applications to associate key-value pairs with visitors.
SessionManagerLayer
A layer for providing Session as a request extension.

Enums§

SessionBackend
Wraps whichever of AnySessionStore/FileSessionStore Config:: session_driver selected, so session_layer always returns the same concrete SessionManagerLayer<SessionBackend> type regardless of which one is active - tower_sessions::SessionManagerLayer<S> is generic over one concrete S, so the alternative to an enum here would be trait- object erasure (Arc<dyn SessionStore>), more machinery for no real benefit over a two-variant match in each trait method.

Functions§

cookie_name
This app’s own session cookie name, derived from Config::app_name - public so larust_testing::TestClient::acting_as can adopt a session by hand-crafting the exact same Cookie header the router’s own session layer (above) would issue, without needing a real /login round trip. Must stay the single source of truth for the name: any second place that re-derives it independently risks drifting out of sync with whatever session_layer actually configured.
resolve_backend
Resolves Config::session_driver into the matching, constructed (but not yet prepared - see session_layer’s own ensure_dir/migrate call for that) SessionBackend variant. Split out from session_layer itself specifically so larust_testing::TestClient can build a handle over the same backend a router’s own session layer resolved to, without duplicating the driver-selection logic (and risking it drifting out of sync) - TestClient::acting_as forges a session by writing directly through this handle, bypassing a real /login round trip, so it has to agree with the router on where sessions actually live. Doesn’t call ensure_dir/migrate itself: a TestClient is always built over a router whose own .with_sessions(...) call already ran them, the same “someone else already prepared this” assumption the database branch has always relied on (TestClient::new never called AnySessionStore::migrate either, even before FileSessionStore existed).
session_layer
Builds the session layer for a Larust app, over pool (typically larust_support::orm::pool()) - or, when Config::session_driver is "file", over a directory instead, pool going unused for this call entirely. Dispatches to whichever of AnySessionStore/ FileSessionStore is active (see this module’s own doc comment), preparing it before returning: the database store’s idempotent CREATE TABLE IF NOT EXISTS, or the file store’s create_dir_all - no separate migration file needed in any app’s database/migrations/ either way.
take
Reads and clears a “flash” value - like session.remove(key), but only actually calls it when key was present. Prefer this for a flash- message read that runs on every page view whether or not one was queued (the common Laravel-style “check for a flashed success/error message on every response” pattern - see demo/app/Http/Controllers/ post_controller.rs’s index for a real example).