redis / redis/fastapi-redis-sdk
Server-side session management
@tishun is already working on this.
Since Sep 10, 2026.
- 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.sessionis synchronous, so nothing can load lazily on first touch - hencestarsessions'load_session(). The middleware is the last place that canawait. No cookie, no Redis call. We never write an unchanged payload. - Two hash fields, two clocks. Field
aholds the absolute TTL and is never refreshed; fielddholds the idle TTL, refreshed on access (hash field expiration). Redis enforces both and we compute neither, so outliving the absolute deadline is unreachable. Fieldaalways carries a TTL, orHTTL's-2is ambiguous. One - pipelined
HGETEXplusHTTLloads and refreshes. Cookiemax-ageismin(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 andrevoke_allverify candidates with a pipelinedHTTLand delete dead ones - two round trips at any count, and no prune job.HLENover-counts, so a bound below a concurrency cap answers inO(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
MULTIholds 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
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Assessment
This issue has not been assessed yet.