ADR-0145: Session lifetimes and session management
- Status: accepted
- Date: 2026-09-30
- Deciders: Mahdi Amirabdollahi
Context
Sessions lived in JDBC (ADR-0123) with one 8-hour inactivity timeout. The console polls and holds an SSE stream, so a tab left open never went idle. Users could not see where they were signed in.
Decision
- Two runtime settings:
security.session.idle-timeout(30 min) andsecurity.session.absolute-lifetime(12 h).SessionLifetimeFilterends a session past either. - Idle means no user activity. The session's
LAST_ACTIVITY_ATmoves only on mutating requests and on requests withX-Studio-Activity: 1, which the UI adds when the user used the pointer or keyboard in the last minute. Spring Session'smaxInactiveIntervalis the storage backstop. SessionAuthentication.establishtakes explicit facts (signed in, authenticated, second factor, address, client) so each path states what it proves.- Users list and end their own sessions; administrators with
user:adminlist and end anyone's. Sessions are identified by a truncated SHA-256 of the session id, never the id. - A password change ends the user's other sessions.
Consequences
- An unattended console signs out after 30 minutes.
- A custom client that wants to stay signed in sends the activity header or makes changes.
Alternatives considered
- Treat every request as activity: polling would keep sessions alive forever.
- Client-side idle logout only: a closed laptop's tab would never send the logout.