redis / redis/fastapi-redis-sdk

Server-side session management

Open
#46 0 comments 0 reactions 1 assignee View on GitHub

@tishun is already working on this.

Since Sep 10, 2026.

enhancement
Dominant language
Python
Stars
357
Forks
20
Avg merge
5d 2h
Merged PRs (30d)
6

Description

Why

Starlette's SessionMiddleware keeps the session in a signed cookie, so nothing on the server knows it exists: no revocation, no server-side expiry, no ID rotation, 4 KB ceiling. starsessions adds a store but makes you call load_session(), gives one clock, and leaves the old ID valid after regenerate_id() until a save() that may never run.

One line enables it: FastAPIRedis(app).lifespan().sessions(). It implements the OWASP session controls and answers fastapi#754.

Scope

Requirements: automatic load and save, idle and absolute expiry enforced by Redis, automatic rotation, revoke one or revoke all, a device listing, an opaque signed cookie, request.session compatibility, def endpoints, telemetry, extensibility, opt-in session events.

Out-of-scope: an in-memory or cookie store, the starsessions contract, compare-and-set, client-side caching, a query-engine index, a renewal timer, a shipped encryptor.

Decisions

  • Eager load, in the middleware. HTTPConnection.session is synchronous, so nothing can load lazily on first touch - hence starsessions' load_session(). The middleware is the last place that can await. No cookie, no Redis call. We never write an unchanged payload.
  • Two hash fields, two clocks. Field a holds the absolute TTL and is never refreshed; field d holds the idle TTL, refreshed on access (hash field expiration). Redis enforces both and we compute neither, so outliving the absolute deadline is unreachable. Field a always carries a TTL, or HTTL's -2 is ambiguous. One
  • pipelined HGETEX plus HTTL loads and refreshes. Cookie max-age is min(idle, HTTL a) - both numbers from Redis.
  • A reverse index that is an upper bound. sessions-of:<subject> holds one field per session, each TTL being that session's absolute deadline. Entries track the absolute clock while sessions usually die of idleness, so listing and revoke_all verify candidates with a pipelined HTTL and delete dead ones - two round trips at any count, and no prune job. HLEN over-counts, so a bound below a concurrency cap answers in O(1).
  • Rotation is detected, never called. The middleware compares a pure principal_of(session) before and after the application, and rotates when it changed and the status is below 400. Writing the identity is signing in; principal_keys=["user_id", "role"] declares privilege. Failing to rotate is the only mistake here that is a vulnerability - and there is no call to forget.
  • Ordering replaces atomicity. Cluster puts these keys in different slots, so no MULTI holds them. Rotation deletes the old key first: a crash signs the user out instead of leaving two valid IDs for one session. Writes hit the session key before the index entry, and re-assert it with the remaining absolute time.
  • Failure is asymmetric. A failed read yields an empty session, so the auth dependency returns 401; a failed write raises SessionStoreError. No driver error reaches callers.
  • Cost: no cookie, zero calls; read-only, one round trip; unchanged, no write.
  • Privacy: no session ID or subject in any log, span or metric label.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.