Skip to content

Session Cookie Guard

session_cookie(*, store, secret, cookie_name, user_builder, realm) — loads sessions from a signed cookie and validates that the session is active.

Signature

def session_cookie(
    *,
    store: SessionStore,
    secret: str | bytes,
    cookie_name: str = "lauren_session",
    user_builder: Callable[[Session], AuthUser | None] | None = None,
    realm: str = "lauren",
) -> type:
    ...

Parameters:

Parameter Type Default Description
store SessionStore Session backend (e.g. InMemorySessionStore).
secret str \| bytes HMAC signing key for the cookie value (see sign_cookie/verify_cookie).
cookie_name str "lauren_session" Cookie to read the session id from.
user_builder callable | None None (Session) -> AuthUser \| None. Default builds from session.user_id plus session.data["roles"]/["scopes"].
realm str "lauren" Surfaced in error responses.

Usage

from lauren_guards import InMemorySessionStore, session_cookie

store = InMemorySessionStore()

SessionGuard = session_cookie(
    store=store,
    secret="my-hmac-secret",
    cookie_name="lauren_session",
)

Logging a user in

Create the session in your login handler, sign it, and set the cookie:

from lauren import Response
from lauren_guards import InMemorySessionStore, session_cookie, sign_cookie

store = InMemorySessionStore()
SECRET = "my-hmac-secret"
SessionGuard = session_cookie(store=store, secret=SECRET)


async def login(request, username: str) -> Response:
    session = await store.create(user_id=username, ttl_seconds=3600)
    signed = sign_cookie(session.id, secret=SECRET)
    return Response.json({"ok": True}).with_cookie(
        "lauren_session", signed,
        http_only=True, secure=True, same_site="lax",
    )

Note the cookie flags: http_only=True keeps JavaScript away from the session id, secure=True restricts it to HTTPS, and same_site="lax" adds CSRF mitigation.

How the guard validates requests

On each request the guard reads the cookie_name cookie, verifies its HMAC signature with secret, looks up the Session in store, and checks it is not expired. It then builds the AuthUser via user_builder (default: session.user_id plus session.data["roles"]/["scopes"]) and stores it on request.state.user.

See Sessions for the SessionStore protocol and cookie utilities.

Production store

Swap InMemorySessionStore for a shared store by implementing the SessionStore protocol — see the Redis-backed example in Sessions.