Auth & sessions
AkurAI/Framework ships a reference authentication feature: cookie-based sessions on the embedded B+tree, a tiny users table, a plain-HTML login form, a protected page, and logout. It is built the same way as the forms demo — validate, store, redirect — and stores nothing in memory, so logins survive a restart.
This is a framework demo, not a hardened auth system. The PRNG and the password hash are deliberately simple and std-only. Read the security caveats before shipping anything real on top of it.
The session model
A session is a row in data/sessions.db, keyed by an opaque session id and holding the username it belongs to plus a created-at timestamp (unix seconds). The id is the only thing the browser ever sees — it is the cookie value.
Users live in a separate data/users.db, keyed by username, storing a salted password hash (never the plaintext). A demo user is seeded on first boot.
| Store | File | Key | Value | | --- | --- | --- | --- | | Sessions | data/sessions.db | opaque session id | { username, created } | | Users | data/users.db | username | { salt, hash } |
Both are Arc<Mutex<BTree>> handles — the same durable, single-writer storage engine the guestbook uses. Every write commits, so a session is durable the moment login returns.
The login / logout / protected-route flow
GET /login → render the login form
POST /login → validate credentials
├─ ok → create session, Set-Cookie, 303 → /account
└─ fail → re-render the form with an error (username kept)
GET /account → if a valid session cookie is present, show the user
otherwise 303 → /login
POST /logout → delete the session, expire the cookie, 303 → /login
The flow is pure progressive enhancement: ordinary <form method="post"> elements, Post/Redirect/Get so a refresh never resubmits, and no JavaScript required. An already-signed-in visitor hitting /login is bounced straight to /account.
The session middleware helper
auth::State::current_user(req) is the middleware/helper that gates protected routes. It reads the Cookie request header, parses out the session value, looks it up in the session store, and returns the username (or None). The /account handler is just:
let Some(username) = state.current_user(req) else {
return Reply::Response(redirect("/login"));
};
The cookie
On success the server sends:
Set-Cookie: session=<id>; HttpOnly; Path=/; SameSite=Lax
| Attribute | Why | | --- | --- | | HttpOnly | JavaScript cannot read the cookie, blunting XSS session theft. | | Path=/ | The session applies to the whole site. | | SameSite=Lax | The cookie rides top-level navigations but not cross-site sub-requests, a baseline CSRF mitigation. |
Logout sends the same cookie with an empty value and Max-Age=0, so the browser drops it immediately, and deletes the row from data/sessions.db.
The demo user
| Username | Password | | --- | --- | | demo | akurai |
Seeded on first boot via an idempotent ensure_user — re-running the server never resets an existing user's password. Visit /login and sign in to see the protected /account page.
Security caveats
This feature exists to show the shape of session auth on the framework's own storage engine, with zero external crates. It is not production-grade:
- Demo-grade PRNG. Session ids are 128-bit values derived from
stdonly —
SystemTime nanos mixed with a per-process atomic counter and the pid, run through a SplitMix64 diffuser. This is CSPRNG-lite, not a cryptographically secure RNG. For real deployments, source session ids from OS randomness.
- Demo-grade password hash. Passwords are stored as a salted, stretched
SHA-1 (reusing the WebSocket handshake's SHA-1). It is salted and iterated, but SHA-1 is fast and not memory-hard — this is not bcrypt or argon2 and must not be described as such.
- TLS terminates at the edge. The cookie is intentionally not marked
Secure, because in the reference deployment HTTPS is terminated by nginx in front of the app. The session cookie's confidentiality in transit relies on that edge TLS layer; if you expose the app directly, add Secure and serve over HTTPS.
- No expiry/rotation. Sessions are kept until logout. A real system would
add idle/absolute timeouts and id rotation on privilege change.