Skip to content

fix: rotate and expire client session identities (#986) - #1042

Merged
DevMuhdishaq merged 1 commit into
Dfunder:mainfrom
danieloche635-bit:fix/986-session-rotation
Oct 19, 2026
Merged

DevMuhdishaq merged 1 commit into
Dfunder:mainfrom
danieloche635-bit:fix/986-session-rotation

Conversation

@danieloche635-bit

Copy link
Copy Markdown
Contributor

Summary

Closes #986.

Sign-in now regenerates the session identifier and invalidates the previous one. The identifier also rotates on every token refresh, is destroyed on logout, and idle/absolute timeouts are enforced both on boot and while the tab is open.

The app uses JWT bearer tokens rather than server-side session cookies, so there is no backend session.regenerate(). This PR adds the equivalent client-side session identity layer in src/lib/session.ts and wires it into every path that changes authentication state. All password, wallet and refresh flows converge on useAuthStore.setSession / setTokens, so hooking the store covers each login form (components/LoginForm.tsx and middleware/auth-middleware.ts do not exist in this repository).

Changes

  • src/lib/session.ts (new)
    • sessionStorage-scoped session record (id, issuedAt, lastActivityAt) generated with crypto.randomUUID() (with getRandomValues/counter fallbacks).
    • rotateSession() creates a fresh id and remembers the old id as invalidated; a fixated pre-auth record cannot become active again, even if it is written back to storage.
    • invalidateSession() on logout/expiry removes both the in-memory and persisted record.
    • SESSION_IDLE_TIMEOUT_MS (30 min) and SESSION_ABSOLUTE_TIMEOUT_MS (8 h); touchSession() extends the idle window.
    • getSessionStatus() returns missing | active | idle | expired and clears timed-out records as a side effect.
  • src/features/auth/stores/useAuthStore.ts
    • setSession (password login, wallet login, registration) rotates the session id after successful auth.
    • setTokens (refresh) rotates the id as well.
    • clearSession (logout, failed revalidation) invalidates it immediately.
  • src/features/auth/services/session.ts
    • bootstrapSession signs out stored tokens whose session is idle/expired, and creates an id for existing token-only sessions (upgrade path).
  • src/features/auth/hooks/useSessionTimeout.ts (new)
    • Records pointerdown/keydown/touchstart/scroll as activity and checks every 30 s; idle/expired sessions are ended via the existing endSession().
    • Mounted once in AuthProvider.
  • Tests
    • src/lib/session.test.ts — 9 tests: creation/persistence, rotation, fixation replay, logout invalidation, idle/absolute timeouts, activity extension.
    • src/features/auth/stores/useAuthStore.test.ts — 3 new tests: rotation on login, rotation on refresh, invalidation on logout (plus existing coverage, 9 total).

Acceptance criteria

  • Session ID is regenerated after login
  • Old session ID is invalidated immediately
  • Session rotation occurs on logout and token refresh (logout invalidates; refresh rotates)
  • Session timeout and idle detection are implemented (boot + runtime)
  • Test asserts session fixation is prevented
  • No session fixation vulnerabilities remain in the auth flow
  • All authentication endpoints rotate session IDs — password, wallet, registration and refresh all go through the store actions

Testing

npx vitest run src/lib/session.test.ts src/features/auth/stores/useAuthStore.test.ts
# 2 files passed, 18 tests passed

npx eslint <changed files>
# clean

npx prettier --check <changed files>
# clean

npm run type-check
# No errors reported in any changed file.

Pre-existing failures on main (not introduced by this PR): src/features/messaging/index.ts, src/stores/useUiStore.ts, src/components/ui/Skeleton.tsx and vite.config.ts contain merge/syntax/type errors, so a fully green project-wide type-check/build is not possible on main. This PR does not touch those files.

Sign-in, wallet login and token refresh now rotate a sessionStorage-backed
session id while invalidating the previous one, so a pre-auth id cannot be
fixated. Logout clears it, and idle (30 min) / absolute (8 h) timeouts are
enforced on boot and by a runtime activity monitor.

🤖 Generated with Codebuff
Co-Authored-By: Codebuff <noreply@codebuff.com>
@drips-wave

drips-wave Bot commented Oct 19, 2026

Copy link
Copy Markdown

@danieloche635-bit Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits.

You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀

Learn more about application limits

@DevMuhdishaq
DevMuhdishaq merged commit af8dce4 into Dfunder:main Oct 19, 2026
0 of 3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Transfer silently ignores failure return value

2 participants