feat(auth): session controls — idle / absolute / concurrent (ADR-0069 D4, P2)#2397
Merged
Conversation
… D4, P2)
- platform-objects: sys_session.{last_activity_at, revoked_at, revoke_reason}.
- service-settings: session_idle_timeout_minutes, session_absolute_max_hours,
max_concurrent_sessions_per_user (all 0 = off).
- plugin-auth:
- customSession enforces idle + absolute per request: touch last_activity_at
(throttled ~1/min); revoke (expire-in-place + revoked_at/revoke_reason) once
the idle window or absolute cap is exceeded.
- sign-in after-hook enforces the concurrent cap: keep the newest N live
sessions, revoke the rest (oldest first).
- revocation expires the session in place so better-auth returns null next
request -> existing 401 -> login redirect; no client change.
Default-off / additive; ADR-0049. better-auth GCs expired sessions, so the
revoke audit is best-effort; the enforcement is not.
Verified live (dogfood): concurrent cap=2 + 3 sign-ins -> oldest session
revoked (revoke_reason=concurrent_cap), 2 newest alive; idle=15m with a
backdated last_activity -> session killed on the next request. Unit:
plugin-auth 203 + service-settings 129 + platform-objects 63 green; full build
incl. strict DTS green.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Contributor
📓 Docs Drift CheckThis PR changes 3 package(s): 15 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
ADR-0069 P2 / D4 — session controls: idle timeout, absolute max lifetime, and a concurrent-session cap.
What
Three new
authsettings (all 0 = off):session_idle_timeout_minutes— sign a user out after inactivity. Enforced incustomSession: touchessys_session.last_activity_at(throttled to ~once a minute) and revokes the session once the idle window is exceeded.session_absolute_max_hours— cap total session lifetime regardless of refresh; revoked oncecreated_atis older than the cap.max_concurrent_sessions_per_user— on sign-in, keep the newest N live sessions and revoke the rest (oldest first).New
sys_sessioncolumns back this:last_activity_at,revoked_at,revoke_reason.Mechanism (no client change)
Revocation expires the session in place (
expires_at→ past +revoked_at/revoke_reason), so better-auth returns no session on the next request → the Console's existing401 → login redirecthandles it. Idle/absolute run incustomSession(the per-request session-validation seam); the concurrent cap runs in the sign-in after-hook.ADR-0049
Default-off / additive (no upgrade behavior change); each setting ships with its enforcement. The existing native
session.expiresIn/updateAgeand/revoke-other-sessionsare kept as-is.Verification
get-session→ no user; DBrevoke_reason=concurrent_cap), the 2 newest stay alive.idle=15mwith a back-datedlast_activity_at→ the session is killed on the next request (get-session→ no user).ADR-0069 status
P1 complete; enforced MFA complete across all surfaces (+ Console UI). P2 now adds session controls. Remaining on #2375: P2 IP allowlist + OIDC trust-list UI, and P3 SAML.
🤖 Generated with Claude Code