persistent "stay signed in" session cookies across every bchen.dev app (both #18
Reference in New Issue
Block a user
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
2026-05-08 — cross-project: persistent "stay signed in" session cookies across every bchen.dev app (both authd-SSO and own-login flows)
User wants: once you sign in to any bchen.dev app, you stay signed in until you explicitly clear your cookies (or hit a logout button). No more "open the laptop next morning and get bounced to /login because the session cookie was a session-only cookie that died with the browser."
Source request (verbatim from user): "for every app (including those using the new authd signin + old individual signin), make it so you stay signed in unless you clear your cookies"
In scope — all 6 apps with auth/session surfaces:
~/authd) — ✅ DONE (PR #7 merged 2026-05-09 at562aca5). 30-day slidingtokencookie + JWT, single mint primitiveissueSessionCookie, mfa-pending guard + logout-path guard preserved.JWT_EXPIRYenv var dropped.~/inventory) — NOT yet an authd client; migration filed as the separate item above (2026-05-08, "migrate inventory authentication to authd … both human login AND MCP"). The migration also rips out inventory's MCP-OAuth-provider surface entirely (per user direction, 2026-05-08). After that lands, inventory has exactly one cookie path —inventory_sessionset by the authd handshake — and one Bearer-token path for MCP traffic, both keyed by authdsub. Persistence work for inventory then becomes "authd SSO cookie +inventory_sessioncookie + a long enoughsessions-table TTL for MCP refresh-token rotations to keep up". Sequence accordingly: do the migration first, then sweep inventory along with the other authd-SSO clients (inventory, buchinese, dashcam) for the long-Max-Age treatment.~/buchinese) — ✅ DONE (PR #3 merged 2026-05-09 at9015328). 30-day persistentbuchinese_sessioncookie + sliding renewal at most once per hour. Family constants reused verbatim. Two-layer logout-resurrection defense (architectural + URL guard).~/nanodrop) — ✅ DONE (PR #4 merged 2026-05-09 ataed9931). 30-day persistentnanodrop_sessioncookie + sliding renewal at most once per hour. Family constants reused verbatim. Stateless-JWT architecture (mirrors authd; nanodrop has no sessions table). Both logout paths URL-guarded.JWT_EXPIRYenv var removed.~/dashcam) — ✅ DONE (PR #2 merged 2026-05-09 at4459450). 30-day persistentdashcam_sessioncookie + sliding renewal at most once per hour. Family constants reused verbatim. Stateful sessions-DB architecture (mirrors buchinese). sessions table gainedexpires_atcolumn with idempotent ALTER +last_seen_atbackfill. Two-layer logout-resurrection defense (architectural + URL guard with query-string strip). Tampered-ciphertext hardening (try/catch wrap returns null instead of 500). Single-mint primitive consolidates the cookie write at exactly one site.~/movement) — ✅ DONE (PR #13 merged 2026-05-10 atbe39c07). 30-day persistentmovement_sessioncookie + sliding renewal at most once per hour. Family constants reused verbatim. Stateless-JWT architecture (mirrors authd/nanodrop; movement has no sessions table). Hard-cut rename fromtoken→movement_session. Both logout paths URL-guarded.JWT_EXPIRYenv var removed.sameSite='strict'preserved (stricter than family default 'lax', kept per never-relax invariant).Out of scope: portman, tradebot — no auth surface (verified by survey on 2026-05-08).
What "stay signed in" means in practice (the spec):
Max-Age/Expiresattribute, which makes the browser drop it when the window closes. Set an explicit long expiry. Recommended default across the family: 30 days, sliding (rolling) — every authenticated request bumps the cookie's expiry forward another 30 days. So an active user effectively never gets logged out; an inactive user's session lapses 30 days after their last visit. The implementer may pick 90 days if there's a reason, but pick one number and use it consistently across all 6 apps so the family feels coherent.auth.bchen.dev(so re-auth on the SSO server isn't required when an app's local session lapses), AND each downstream app's own session cookie (so the app doesn't bounce through OAuth on every visit). If authd issues refresh tokens, ensure the access-token-refresh path is wired up so a still-valid refresh token avoids bouncing the user to/login.Secure,HttpOnly,SameSite=Lax(orStrictwhere the app already uses it). Cookie value still rotates on login (no fixation). Idle-rolling expiry uses the existing session token; do not extend a token after sign-out.Set-Cookie: <name>=; Max-Age=0sent to the browser. "Stay signed in unless you clear your cookies" = until cookies expire OR the user actively clears them OR the user clicks logout.Plan / approach:
cookie,Set-Cookie,maxAge,max_age,expires,session). Note current cookie attributes and current server-side session lifetime.SESSION_TTL_DAYS = 30) so it's tunable per repo without hunting through the codebase.Acceptance:
/login.)Secure,HttpOnly,SameSiteattributes preserved.mainvia the implementer pipeline.Notes for the implementer:
~/features.mdif any per-app implementation hits a snag that warrants its own item.inventory PR #5andauthd PR #6work shows the family is converging on shared conventions; this is in the same spirit. Keep the chosenSESSION_TTL_DAYSconstant identical across all 6 repos so future audits are trivial.Source: user via reporter chat (2026-05-08).