Skip to content

feat(auth): session controls — idle / absolute / concurrent (ADR-0069 D4, P2)#2397

Merged
os-zhuang merged 1 commit into
mainfrom
auth/adr-0069-session-controls
Jun 27, 2026
Merged

feat(auth): session controls — idle / absolute / concurrent (ADR-0069 D4, P2)#2397
os-zhuang merged 1 commit into
mainfrom
auth/adr-0069-session-controls

Conversation

@os-zhuang

Copy link
Copy Markdown
Contributor

ADR-0069 P2 / D4 — session controls: idle timeout, absolute max lifetime, and a concurrent-session cap.

What

Three new auth settings (all 0 = off):

  • session_idle_timeout_minutes — sign a user out after inactivity. Enforced in customSession: touches sys_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 once created_at is 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_session columns 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 existing 401 → login redirect handles it. Idle/absolute run in customSession (the per-request session-validation seam); the concurrent cap runs in the sign-in after-hook.

Note: there is a one-request grace for idle/absolute (the request that trips the limit resolves, then revokes — the next request is rejected). And better-auth garbage-collects expired sessions, so the revoke_reason audit is best-effort; the enforcement (session killed) is not.

ADR-0049

Default-off / additive (no upgrade behavior change); each setting ships with its enforcement. The existing native session.expiresIn/updateAge and /revoke-other-sessions are kept as-is.

Verification

  • Unit: plugin-auth 203 + service-settings 129 + platform-objects 63 green; full build incl. strict DTS green. New tests cover idle revoke, absolute revoke, last_activity touch, already-revoked no-op, and concurrent-cap oldest-eviction.
  • Live dogfood:
    • Concurrent: cap=2 + 3 sign-ins → the oldest session is revoked (get-session → no user; DB revoke_reason=concurrent_cap), the 2 newest stay alive.
    • Idle: idle=15m with a back-dated last_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

… 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>
@vercel

vercel Bot commented Jun 27, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
spec Ready Ready Preview, Comment Jun 27, 2026 5:39pm

Request Review

@github-actions github-actions Bot added documentation Improvements or additions to documentation tests tooling size/m labels Jun 27, 2026
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 3 package(s): @objectstack/platform-objects, @objectstack/plugin-auth, packages/services.

15 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:

  • content/docs/concepts/implementation-status.mdx (via @objectstack/plugin-auth)
  • content/docs/concepts/packages.mdx (via @objectstack/platform-objects, @objectstack/plugin-auth)
  • content/docs/concepts/setup-app.mdx (via @objectstack/platform-objects)
  • content/docs/getting-started/cli.mdx (via @objectstack/plugin-auth)
  • content/docs/guides/auth-sso.mdx (via @objectstack/plugin-auth)
  • content/docs/guides/authentication.mdx (via @objectstack/plugin-auth)
  • content/docs/guides/kernel-services.mdx (via @objectstack/plugin-auth)
  • content/docs/guides/packages.mdx (via @objectstack/platform-objects, @objectstack/plugin-auth, packages/services)
  • content/docs/guides/plugins.mdx (via @objectstack/plugin-auth)
  • content/docs/guides/production-readiness.mdx (via @objectstack/plugin-auth)
  • content/docs/guides/runtime-services/audit-service.mdx (via packages/services)
  • content/docs/guides/runtime-services/index.mdx (via packages/services)
  • content/docs/guides/runtime-services/settings-service.mdx (via packages/services)
  • content/docs/protocol/objectos/i18n-standard.mdx (via packages/services)
  • content/docs/releases/v9.mdx (via @objectstack/plugin-auth)

Advisory only. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs origin/main → pass the list as args.docs.

@os-zhuang
os-zhuang merged commit 3209ec6 into main Jun 27, 2026
16 checks passed
@os-zhuang
os-zhuang deleted the auth/adr-0069-session-controls branch June 27, 2026 17:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation size/m tests tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant