# Remember-me uses a separate long-lived token

- **Pattern:** `ab-002229` (`saas-authentication.session-management.remember-me-separate-token`)
- **Severity:** medium
- **Lifecycle:** active
- **Last modified:** 2026-04-18
- **Canonical URL:** https://auditbuffet.com/patterns/ab-002229
- **License:** CC-BY-4.0 — attribute to AuditBuffet Pattern Catalog (https://auditbuffet.com/patterns/ab-002229)

## Why it matters

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.

## Severity rationale

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.

## Remediation

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:

```ts
// 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.

## Detection

- **ID:** `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:

  ```ts
  // 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.

---

## External references

- cwe CWE-613
- cwe CWE-287
- owasp A07

Taxons: access-control

HTML version: https://auditbuffet.com/patterns/ab-002229
