Extending the session lifetime to 30 days to implement 'remember me' means a stolen cookie is valid for a month with no way to revoke it on a per-device basis. CWE-613 (Insufficient Session Expiration) and CWE-287 (Improper Authentication) both cover this — the regular session has effectively lost its expiry guarantee. OWASP ASVS V3 (Session Management) treats persistent-login tokens as a separate authenticator class that must be individually revocable. A separate remember-me token stored server-side can be deleted individually, ending persistent login on one device without forcing a logout everywhere.
Medium because the defect requires a stolen persistent cookie to be exploited, but once stolen the session lasts weeks with no user-accessible revocation mechanism.
Issue a separate, revocable remember-me token distinct from the regular session cookie. Keep the regular session at its normal short TTL and use the remember-me token only to silently re-establish it:
// On login with remember-me checked:
const rememberToken = crypto.randomBytes(32).toString('hex')
await db.rememberTokens.create({
data: { token: hash(rememberToken), userId, expiresAt: thirtyDaysFromNow }
})
res.cookie('remember_me', rememberToken, {
maxAge: 30 * 24 * 60 * 60 * 1000,
httpOnly: true, secure: true, sameSite: 'lax'
})
// Regular session cookie still expires in 1–7 days
On per-device logout, delete the specific remember token row. This leaves other devices unaffected while fully invalidating the target device.
ID: saas-authentication.session-management.remember-me-separate-token
Severity: medium
What to look for: If the application has a "remember me" feature (checkbox on login, persistent login option), examine how it is implemented. A separate, revocable "remember-me token" should be stored server-side and in a dedicated cookie distinct from the regular session cookie. The regular session should still have a short expiry; only the remember-me token triggers a session refresh. If no "remember me" feature exists, this check is N/A. Count all instances found and enumerate each.
Pass criteria: Remember-me functionality uses a separate, server-side-tracked token that can be individually revoked. The token is stored in a dedicated HttpOnly cookie. The regular session has a shorter lifetime, and the remember-me token is used only to establish a new session, not to directly authenticate API requests. At least 1 implementation must be confirmed.
Fail criteria: "Remember me" is implemented simply by setting a very long maxAge on the main session cookie without a separate revocable token. Or the remember-me token is stored in localStorage.
Skip (N/A) when: No "remember me" or persistent login feature detected. Signal: login form has no such option, auth library config has no extended session handling.
Detail on fail: "Remember-me implemented by setting session maxAge to 30 days on the primary session cookie with no separate revocable token — compromised sessions cannot be individually revoked".
Remediation: A long-lived session cookie without a separate token means a stolen cookie is valid for weeks. Instead, use a token series approach:
// On login with "remember me" checked:
const rememberToken = crypto.randomBytes(32).toString('hex')
await db.rememberTokens.create({
data: { token: hash(rememberToken), userId, expiresAt: thirtyDaysFromNow }
})
// Set dedicated remember-me cookie (separate from session cookie)
res.cookie('remember_me', rememberToken, {
maxAge: 30 * 24 * 60 * 60 * 1000,
httpOnly: true, secure: true, sameSite: 'lax'
})
// Regular session still has short TTL (e.g., 1-7 days)
On each request, check both the session cookie and, if the session expired, the remember-me cookie to silently refresh. This allows individual device logout (delete the remember token record) without affecting other sessions.