Skip to content

Session

LoboGuardian 🐺 edited this page Jul 11, 2026 · 7 revisions

Session Management in HTeaLeaf

HTeaLeaf provides a lightweight built-in session system that allows you to persist data between requests per user, without depending on external libraries or databases.


How it works internally

When a new client connects (or presents an unknown/expired session cookie), HTeaLeaf:

  1. Generates a fresh session ID (a server-side UUID — client-supplied IDs are never trusted, which prevents session fixation).
  2. Stores a Session object associated with that ID on the server, with an expiration timestamp.
  3. Sends a cookie to the client containing the session ID, flagged HttpOnly; SameSite=Lax; Path=/ (plus Secure when the request came over TLS).
  4. For every subsequent request, HTeaLeaf retrieves the stored session using that cookie and slides its expiration forward.

The result is a simple but powerful mechanism to maintain per-user state.

Expiration and eviction (TTL)

Sessions are managed by a SessionManager that keeps them in an OrderedDict, ordered by last use:

  • Every session has a TTL (max_ttl, default 10,000 seconds). Each access refreshes the expiration (sliding TTL), so active users are never logged out.
  • Expired sessions are lazily evicted: reading an expired session removes it, and the manager periodically sweeps expired entries from the front of the LRU order.
  • Session.ttl() returns the remaining seconds for a session.

The session object

Route handlers receive a SessionData object, which behaves like a Python dictionary but also supports attribute-style access.

session.has(attr)      # check if attr exists, returns True or False
session[attr] = value  # set attr to value
session[attr]          # get the value; raises if attr does not exist
session.userName       # attribute-style access to the same data

Function route, session injection

If session exists as an argument of a route handler, HTeaLeaf will inject the session automatically:

from htealeaf.server.utils import redirect

@app.route("/login")
def login(session, req: Request):
    user = req.form()
    if not user or "userName" not in user:
        return 401, "unauthorized"

    # Store user data in the session
    session["userName"] = user["userName"]
    return redirect("/")

Security notes

  • Session IDs are server-generated UUIDs; a cookie with an unknown or expired ID is discarded and replaced with a fresh one (no session fixation).
  • The cookie is HttpOnly (not readable from JavaScript) and SameSite=Lax; Secure is added automatically on TLS connections.
  • Sessions are not persisted — they live only in server memory and are lost on restart.

Future features

  • Persisting sessions
  • Signed/encrypted cookies
  • Max-Age on the session cookie matching the server-side TTL

Next: LocalState

Clone this wiki locally