Context
Members have to log in again essentially every time they visit the site. For a ~500-user community app used in bursts (shift signups, event weeks), that's real friction — especially on mobile where the OAuth round-trip is clunky.
Problem / Motivation
Two compounding causes, confirmed in code:
- Every production sign-in issues a browser-session cookie. All sign-in paths pass
isPersistent: false, so the auth cookie has no Expires attribute and dies when the browser fully closes:
AccountController.cs:70 — ExternalLoginSignInAsync(..., isPersistent: false, ...) (the main Google login path)
AccountController.cs:198, 234, 291, 471, 537 — the account-linking / first-login / merge variants
- (The password path at
AccountController.cs:595 already uses isPersistent: true — the inconsistency shows the intent was never "expire aggressively".)
- No explicit cookie lifetime is configured.
ConfigureApplicationCookie (Program.cs:141-148) sets HttpOnly/Secure/SameSite but no ExpireTimeSpan/SlidingExpiration, so even a persistent cookie would ride on Identity's implicit default (14-day sliding) rather than a deliberate policy.
Proposed Solution
- Flip the production sign-in calls to
isPersistent: true. No "Remember me" checkbox — the Google OAuth flow has no credential form to hang it on, and default-persistent matches user expectation for this kind of app.
- Set an explicit, deliberate policy in
ConfigureApplicationCookie: ExpireTimeSpan = 7 days, SlidingExpiration = true (any visit inside the window extends it; absence for 7 days requires re-login).
- Revocation stays intact: explicit logout works unchanged; suspended/non-Active users are already bounced per-request by
MembershipRequiredFilter regardless of cookie lifetime; Identity's security-stamp validation (30-min default) kills cookies on server-side invalidation.
- Gate/kiosk sessions already have explicit sign-out affordances ("End shift", kiosk
logout command), so shared-device risk is managed; no carve-out needed.
DevLoginController — implementer's choice; persistence there is harmless (dev/preview only).
Decision (Peter, 2026-07-13): 7-day sliding window for now; can lengthen later if re-login friction is still felt.
- Dev-login persistence — left to the implementer.
Acceptance Criteria
Key files: src/Humans.Web/Controllers/AccountController.cs, src/Humans.Web/Program.cs, src/Humans.Web/Controllers/DevLoginController.cs
Context
Members have to log in again essentially every time they visit the site. For a ~500-user community app used in bursts (shift signups, event weeks), that's real friction — especially on mobile where the OAuth round-trip is clunky.
Problem / Motivation
Two compounding causes, confirmed in code:
isPersistent: false, so the auth cookie has noExpiresattribute and dies when the browser fully closes:AccountController.cs:70—ExternalLoginSignInAsync(..., isPersistent: false, ...)(the main Google login path)AccountController.cs:198, 234, 291, 471, 537— the account-linking / first-login / merge variantsAccountController.cs:595already usesisPersistent: true— the inconsistency shows the intent was never "expire aggressively".)ConfigureApplicationCookie(Program.cs:141-148) sets HttpOnly/Secure/SameSite but noExpireTimeSpan/SlidingExpiration, so even a persistent cookie would ride on Identity's implicit default (14-day sliding) rather than a deliberate policy.Proposed Solution
isPersistent: true. No "Remember me" checkbox — the Google OAuth flow has no credential form to hang it on, and default-persistent matches user expectation for this kind of app.ConfigureApplicationCookie:ExpireTimeSpan = 7 days,SlidingExpiration = true(any visit inside the window extends it; absence for 7 days requires re-login).MembershipRequiredFilterregardless of cookie lifetime; Identity's security-stamp validation (30-min default) kills cookies on server-side invalidation.logoutcommand), so shared-device risk is managed; no carve-out needed.DevLoginController— implementer's choice; persistence there is harmless (dev/preview only).Decision (Peter, 2026-07-13): 7-day sliding window for now; can lengthen later if re-login friction is still felt.
Acceptance Criteria
UserState) user with a live cookie is still redirected to/User/Statuson next requestKey files:
src/Humans.Web/Controllers/AccountController.cs,src/Humans.Web/Program.cs,src/Humans.Web/Controllers/DevLoginController.cs