Stage 7 · Master
Caching and Rate Limiting
Session Storage in Redis
If Meridian keeps browser-facing session state on the server side, the natural owner is the gateway and the natural store is Redis keyed by tenant context.
Why Session State Belongs at the Edge
Meridian-web never calls identity-service, community-service, or billing-service directly; it addresses only the gateway. If the platform adopts server-side browser session state for login continuity, CSRF protection, or refresh-token references, the gateway is therefore the correct owner. Internal services should receive authenticated identity and tenant context, not browser cookie semantics.
The current scaffold does not implement login, Auth0 verification, cookie handling, or Redis-backed sessions. This lesson documents the intended session model that would sit beside the gateway once authentication is introduced.
What Goes in a Session Record
Two principles keep the record small and safe. First, Redis stores opaque references such as a refresh token handle or session version rather than raw third-party credentials when possible. Second, membership and authorization changes must be observable. A MembershipVersion or similar revision marker allows the gateway to invalidate old sessions when identity-service changes a user's tenant role.
Redis Key and Cookie Shape
Cookie: meridian_session=<opaque_session_id>; HttpOnly; Secure; SameSite=Lax
Redis key:
gateway:session:tenant:{tenant_id}:session:{session_id}The browser carries only the opaque session identifier. The tenant-aware session record lives server-side, where it can be revoked, rotated, or expired without trusting the client to discard a JWT promptly.
| Approach | Strength | Trade-off |
|---|---|---|
| Pure self-contained JWT in the browser | No server-side lookup on each request | Harder revocation and role-change invalidation |
| Gateway session ID + Redis record | Central revocation, rotation, and membership change handling | Requires Redis availability and a lookup on protected requests |
| Session record per service | Local autonomy | Breaks the single-entrypoint model and duplicates auth state |
Logout, Rotation, and Expiry
The operational benefit of server-side Redis sessions is lifecycle control. Logout becomes a key delete. Refresh rotation becomes an atomic update of RefreshRef plus a TTL refresh. Tenant suspension or membership removal becomes a targeted invalidation of that tenant's or user's session keys. These are all difficult to do reliably with long-lived, purely client-side tokens.
apps/gateway/internal/session/store.gocreateResponsibility: Loads, saves, rotates, and deletes tenant-scoped session records in Redis.
Why now: Session lifecycle rules should live behind a small dedicated adapter instead of being scattered through middleware and handlers.
Connects to: Works with the gateway middleware chain once authentication is added after the current /healthz-only phase.
apps/gateway/internal/middleware/session.gocreateResponsibility: Reads the session cookie, loads the Redis record, and injects user and tenant context for downstream routing.
Why now: Cookie parsing and Redis lookups are edge concerns, not business-service concerns.
Connects to: Populates context that later maps to libs/platform/tenancy and authorization checks.
The Decision
- If server-side session storage is adopted, the gateway is the owner because it is the only browser-facing service.
- Redis stores tenant-scoped session records keyed by an opaque cookie identifier, not raw business payloads.
- tenant_id is mandatory in the stored record and in the Redis key namespace.
- The main payoff is lifecycle control: logout, role changes, token rotation, and tenant suspension become explicit invalidation operations.
Mark this lesson complete to store local progress and unlock a cleaner resume path the next time you visit.