Skip to main content

JWT Session Management

Relay stores JWT sessions in the cache backend (Redis in production, in-memory for development) so tokens can be revoked across the cluster in near real time.

Session Registry​

Sessions persist through src/services/session_store.py and include:

  • session_id, user_id, and timestamps (created_at, last_active_at, expires_at)
  • network context (ip_address, user_agent)
  • token catalogue with per-token JTI, type, issued time, and expiry
  • revocation metadata (revoked, revoked_at, revoke_reason)

The store maintains a user → sessions index (user-sessions:{user_id}) so that all sessions for a user can be revoked atomically. TTL derives from the refresh expiry (minimum 60 seconds) and records update asynchronously whenever JWTs are issued or validated.

Runtime Integration​

SecureJWTAuth wires persistence hooks whenever access/refresh tokens are created or validated. Revoking a session updates both the in-memory tracker and the persistent store. The API dependency get_current_user_from_token checks the store on every request to honour revocations across nodes.

Key entry points:

  • src/security/jwt_auth.py — session persistence hooks
  • src/api/routes/jwt_auth.py — login/refresh/logout wiring and session APIs
  • src/services/session_store.py — cache-backed session registry

API Surface​

New endpoints under /auth expose the persisted state:

  • GET /auth/sessions — list active sessions for the authenticated user
  • DELETE /auth/sessions/{session_id} — revoke a specific session
  • POST /auth/logout — supports revoke_all_sessions and persists revocation to the registry

Example response:

[
{
"session_id": "b7…",
"created_at": "2025-09-21T19:22:00+00:00",
"last_active_at": "2025-09-21T19:28:12+00:00",
"expires_at": "2025-09-22T19:22:00+00:00",
"revoked": false,
"ip_address": "203.0.113.10",
"user_agent": "Mozilla/5.0",
"tokens": [
{"token_jti": "a1…", "token_type": "access"},
{"token_jti": "d4…", "token_type": "refresh"}
]
}
]

Operational Notes​

  • Cache TTL — A session expires when the associated refresh token expires; the cache key inherits that TTL.
  • Revocation propagation — Calls to revoke_session, revoke_user_sessions, or the logout endpoint mark records as revoked and prune the user index. get_current_user_from_token denies future requests against revoked sessions immediately.
  • Audit support — Combine this guide with /auth/sessions exports to satisfy zero-trust audit requirements.

Verification​

Run the integration suite to confirm the behaviour end-to-end:

pytest tests/integration/test_auth_session_revocation.py

For a lighter smoke run:

python3 scripts/monitoring/validate_monitoring_stack.py

Both commands ensure the session registry is wired correctly and that the persisted metadata survives logout flows.