Explorer sessions default to 24 hours absolute, 12 hours idle - #23
Merged
Merged
Conversation
Explorer's app session no longer needs to carry the "how often do users log in" burden: while the central Auth session is live, an expired Explorer session is renewed by a silent redirect through the code handoff. Auth's central session is moving to 30 days, so Explorer's own session becomes the short, bounding one at one day absolute and 12 hours idle, replacing 12 hours and 60 minutes. Problem The 60-minute idle limit was set when the Explorer session was the login users felt. With Auth at 30 days it is not; the app limit only governs how long a stolen Explorer cookie is useful and how often Explorer re-checks with Auth that the account is still enabled. Sixty minutes of idle bought nothing over 12 hours for that purpose, while forcing a redirect and fresh access-list check after every lunch break. Fix - DEFAULT_IDLE_SECONDS 3600 -> 43200, DEFAULT_ABSOLUTE_SECONDS 43200 -> 86400. The EXPLORER_SESSION_* env knobs are unchanged and still override; bootstrap.sh and .env.example carry the new defaults. - A comment at the constants explains the two-layer model and points to Auth's "Application session conventions", which records the rule for every service. - README and DEPLOYMENT tables and the session prose updated to match. Tests - The Set-Cookie test asserts Max-Age=86400; the store-level idle and touch tests build the store with explicit values and are unchanged. - ruff check, ruff format --check, pytest (113 passed). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
jzhao234
added a commit
to ElcanoTek/fleet
that referenced
this pull request
Sep 15, 2026
…1508) ## TLDR The `elcano_session` cookie was a stateless HMAC valid for fourteen days with no notion of inactivity. Under Elcano Auth v2 it is an application session that renews silently through the OIDC handoff while the user's 30-day central session is live, so its job is to bound a stolen cookie and re-check the account with Auth, not to decide how often people log in. It now carries an idle deadline next to the absolute one (one day / twelve hours, the convention Explorer and Lens follow), both are enforced on every request, and the proxy re-mints the cookie on activity. Companion: ElcanoTek/auth#30, ElcanoTek/explorer#23, ElcanoTek/lens#24. ## Problem `SessionPayload` had a single `exp` at mint + 14 days. Nothing recorded activity, so idle sessions never ended early, and fourteen days is out of line with the one-day / twelve-hour application-session convention in `auth/docs/AUTH_V2_IMPLEMENTATION.md`. Fleet is stateless, so an idle limit can only live inside the cookie. ## Fix - `SessionPayload` gains `idle`. `exp` is the absolute deadline (`sessionAbsoluteSeconds`, one day), copied on re-mint and never extended; `idle` is `min(now + 12h, exp)`. - `verifySessionToken` refuses a token whose `idle` or `exp` has passed, and a signed token with no `idle` claim. Pre-deploy cookies are not grandfathered, the same call ADR-0041 made: **every user is signed out once at deploy.** Central-Auth users are signed back in without a prompt; password users log in once more. - `refreshSessionCookie` re-signs with a later `idle` when the last mint is over `sessionTouchSeconds` (60) old, preserving email, exp, epoch, source, issuer, subject, with `Max-Age` = remaining absolute life and `Secure` following the request. No-op for `elcano_auth` sessions, under a minute, or once `idle` sits on `exp`. - The proxy calls it on every authenticated pass-through (pages and `/api`), never on redirects, 401s, public routes or bearer-only requests. - Both mint paths share `signSessionPayload`; the mocked e2e cookie minter mirrors the new claim. - ADR-0064 records the decision (amends ADR-0041); `DEPLOYMENT.md` "Ending a session" updated. ## Tests - `auth.test.ts`: mint deadlines; idle refusal ahead of exp; refusal without `idle`; no re-mint under a minute; re-mint after a minute keeps every identity claim and sets httpOnly/lax/secure/path and Max-Age; activity never moves exp; re-minting stops once capped; `elcano_auth` untouched; Secure follows a plain-HTTP request. Each fails on the previous code. - `proxy.test.ts`: cookie touched exactly once with `(request, response, session)` on an authenticated pass-through, never otherwise. - `npm run typecheck`, `npm run lint`, `npx vitest run`: 1625 passed. The 4 failures in `useDashboardData.test.ts` (tag-catalogue freshness) fail identically on an untouched `origin/main` worktree and are unrelated. `npm run build` and the mocked Playwright suite are left to CI. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
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.
TLDR
While the central Auth session is live, an expired Explorer session is renewed by a silent redirect through the code handoff, so Explorer's own limits govern stolen-cookie blast radius, not login frequency. With Auth moving to a 30-day central session (ElcanoTek/auth#30), Explorer's defaults move from 12h absolute / 60min idle to 24h absolute / 12h idle.
Problem
The 60-minute idle limit was chosen when this session was the login users felt. It is not any more; the app limit only bounds a stolen cookie and sets how often Explorer re-checks the account with Auth. Sixty minutes bought nothing over twelve hours for that and forced a redirect plus access-list check after every break.
Fix
DEFAULT_IDLE_SECONDS3600 → 43200,DEFAULT_ABSOLUTE_SECONDS43200 → 86400.EXPLORER_SESSION_*env knobs unchanged;bootstrap.shand.env.examplecarry the new defaults.Tests
Max-Age=86400; store-level idle/touch tests use explicit values and are unchanged.ruff check,ruff format --check,pytest(113 passed).🤖 Generated with Claude Code