fix(auth): keep active sessions alive and add stay-signed-in (#1711)

This commit is contained in:
Anso
2026-07-28 07:36:50 -04:00
committed by GitHub
parent 2d88d9f8a8
commit 681ecc7047
20 changed files with 775 additions and 95 deletions
+5
View File
@@ -23,6 +23,11 @@ export const MAX_ASSIGNMENTS = 1000;
// Session cookies
export const COOKIE_NAME = 'sencho_token';
export const SESSION_COOKIE_MAX_AGE_MS = 24 * 60 * 60 * 1000; // 24 hours
export const REMEMBER_SESSION_MAX_AGE_MS = 30 * 24 * 60 * 60 * 1000; // 30 days, "stay signed in"
// Sliding-refresh window: a user-session token with less than this much life
// left gets silently reissued with a fresh full TTL, so continued activity
// never runs into the hard expiry. See middleware/auth.ts::authMiddleware.
export const SESSION_REFRESH_THRESHOLD_MS = 60 * 60 * 1000; // 1 hour
export const MFA_PENDING_COOKIE_NAME = 'sencho_mfa_pending';
export const MFA_PENDING_SCOPE = 'mfa_pending';
export const MFA_PENDING_TTL_MS = 5 * 60 * 1000; // 5 minutes to complete the challenge
+7 -3
View File
@@ -1,15 +1,19 @@
import type { Request } from 'express';
import { SESSION_COOKIE_MAX_AGE_MS } from './constants';
/** True when the request arrived over HTTPS, either directly or via a trusted TLS-terminating proxy. */
export const isSecureRequest = (req: Request): boolean => {
return req.secure || req.headers['x-forwarded-proto'] === 'https';
};
/** Cookie options derived from the current request (secure flag follows the connection). */
/**
* Cookie options derived from the current request (secure flag follows the
* connection). Lifetime is deliberately not included: each caller sets its own
* `maxAge` (session cookies vary between the default and "stay signed in", the
* MFA-pending cookie is minutes long), so a shared default here would only ever
* be overridden or misread.
*/
export const getCookieOptions = (req: Request) => ({
httpOnly: true,
secure: isSecureRequest(req),
sameSite: 'strict' as const,
maxAge: SESSION_COOKIE_MAX_AGE_MS,
});