Add server-side session inactivity timeout - #513
Open
parndt wants to merge 4 commits into
Open
Conversation
Enforces a per-token inactivity timeout for devise_token_auth sessions, addressing the pentest finding that sessions stay valid after >30 min idle. Token rotation is off (change_headers_on_each_request = false) to avoid batch write-contention, so DTA's native sliding expiry is unavailable. Instead: - token_activities table stores (user_id, client_id, last_activity_at), one row per live token. It lives off the users row and outside PaperTrail so activity writes don't reintroduce contention or version noise. - TokenActivityEnforcement is a read-only before_action that rejects any request whose token row is stale or missing (fail closed), deleting the stale row rather than writing to users.tokens on the hot path. - POST /auth/activity is a client heartbeat, the only writer, coalesced so the write rate stays ~1 per token per window. Enforcement runs first, so a late ping cannot resurrect an already-expired session. - User#reconcile_token_activities (after_save) keeps the row set in step with the tokens hash, covering login, sign-out, password-reset pruning and max_number_of_devices eviction in one seam. - Thresholds live in config/initializers/session_timeout.rb (30 min timeout, 2 min coalesce window). Existing tokens are backfilled at deploy so no live session is force-expired. The client heartbeat (interaction-gated ping to /auth/activity) is still to be wired up in the SPA.
The password-change prune (remove_tokens_after_password_reset) is a before_save, so User#reconcile_token_activities - an after_save - sees the already-pruned tokens hash and drops the activity rows for the invalidated sessions in the same transaction. Pins that projection, and makes the forward-referencing comments already in this spec true.
Base automatically changed from
sg-dev-invalidate-sessions-on-pw-change
to
sg-dev
July 21, 2026 07:49
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.
Enforces a per-token inactivity timeout for devise_token_auth sessions,
addressing the pentest finding that sessions stay valid after >30 min idle.
Token rotation is off (change_headers_on_each_request = false) to avoid
batch write-contention, so DTA's native sliding expiry is unavailable.
Instead:
one row per live token. It lives off the users row and outside PaperTrail
so activity writes don't reintroduce contention or version noise.
request whose token row is stale or missing (fail closed), deleting the
stale row rather than writing to users.tokens on the hot path.
the write rate stays ~1 per token per window. Enforcement runs first, so a
late ping cannot resurrect an already-expired session.
the tokens hash, covering login, sign-out, password-reset pruning and
max_number_of_devices eviction in one seam.
2 min coalesce window). Existing tokens are backfilled at deploy so no live
session is force-expired.
before_save, so User#reconcile_token_activities - an after_save - sees the
already-pruned tokens hash and drops the activity rows for the invalidated
sessions in the same transaction. This pins that projection, and makes the
forward-referencing comments already in this spec true.
The client heartbeat (interaction-gated ping to /auth/activity) is still to
be wired up in the SPA.