trackslash
TRACK-44 P2

Aggregate web sessions on the Tokens page with bulk revoke

0
All issues

Description

Problem

The Tokens page lists every web session token as an individual row. These are implementation details of browser sign-ins and can create a noisy, repetitive list that makes user-created tokens harder to scan and manage.

Proposed direction

Hide individual web-session entries from the main token list and represent them as one aggregate item instead. The aggregate should show how many active web sessions exist and provide a single action to revoke them all.

Acceptance criteria

  • Individual web session tokens are not shown as separate rows on the Tokens page.
  • Active web sessions are represented by one compact aggregate row or section with an accurate session count.
  • The aggregate provides a clear “Revoke all web sessions” action.
  • Bulk revocation requires confirmation and makes it explicit whether the current browser session will also be revoked.
  • After a successful revoke, the page reflects the updated session state; failures are surfaced without implying success.
  • Non-web-session tokens remain individually visible and retain their existing revoke behavior.
  • Add coverage for aggregation, an empty session state, successful bulk revocation, and failure handling.

Sub-issues

0

Linked issues

0

GitHub

0

No branches or pull requests linked.

Comments

1
Bradley

Most of this shipped in #139 (aggregate row, bulk revoke, confirmation, htmx redirect). The remaining gap was the count itself.

Bug: sessions get a 7-day expiry (TRACK_SLASH_SESSION_TTL), but the sweep in 0040_session_token_expiry.sql only revokes sessions older than three years. uiPartitionAuthTokens counted anything unrevoked, so expired-but-unswept sessions were reported as active. Signing in from a new browser weekly builds up to ~150 "active web sessions" when exactly one still authenticates.

Fix (#147):

  • AuthToken.Live(now) names the predicate AuthenticateToken already applies in SQL — unrevoked and unexpired — so the listing and the auth path cannot drift.
  • uiPartitionAuthTokens counts sessions with that predicate.
  • Zero case reads "No active web sessions" rather than "0 active web sessions"; that is what an API-token-only account sees.

Coverage: AuthToken.Live and uiPartitionAuthTokens at 100%. New tests for the expiry boundary, aggregation, an expired session being ignored, and the empty state. Successful bulk revoke and the htmx path were already covered.

Full ./internal/... suite passes against Postgres.