You're designing remember-me for a security-sensitive production app. What are the key risks and how do you harden the configuration?
answer
- cookie = bearer credential; theft = takeover
- HTTPS + Secure + HttpOnly + SameSite
- persistent tokens => rotation + revoke + theft detect
- short validity, stable externalized key
- step-up: fullyAuthenticated for sensitive actions
basics
~20 sThe core risk is a stolen long-lived cookie granting account access. Harden by serving only over HTTPS with Secure and HttpOnly cookies, using persistent tokens for revocation and theft detection, keeping validity short, setting a stable secret key, and gating sensitive actions behind fullyAuthenticated so remember-me users must re-enter their password.
solid answer
~40 sRemember-me trades security for convenience: a valid cookie is a bearer credential, so theft = account takeover until expiry. Treat the cookie as sensitive. Always require HTTPS and set the cookie Secure + HttpOnly (and SameSite=Lax/Strict) so it can't leak over plaintext or to JavaScript/XSS. Prefer PersistentTokenBasedRememberMeServices for per-device revocation and cloned-cookie detection (CookieTheftException) over the stateless TokenBased strategy, which can only be revoked by a global password change. Keep tokenValiditySeconds modest and set a stable, secret key (externalized, not committed) shared across cluster nodes and matched between services and provider. Crucially, treat remember-me as a weaker trust level: use isFullyAuthenticated()/fullyAuthenticated to force a fresh password prompt before password changes, payments, or privilege changes. Clear the cookie on logout, provide a 'sign out other devices' path, and consider disabling remember-me for admin/high-privilege accounts.
code
java · 19 lines@Bean
SecurityFilterChain security(HttpSecurity http,
PersistentTokenRepository repo,
UserDetailsService uds) throws Exception {
http
.rememberMe(rm -> rm
.key(System.getenv("REMEMBER_ME_KEY")) // externalized secret
.tokenRepository(repo) // persistent: rotation + theft detection
.userDetailsService(uds)
.tokenValiditySeconds(3 * 24 * 3600) // 3 days, not 14
.useSecureCookie(true)) // Secure flag; HTTPS only
.authorizeHttpRequests(auth -> auth
// step-up: remembered users must re-authenticate for sensitive paths
.requestMatchers("/account/password", "/account/mfa", "/admin/**")
.fullyAuthenticated()
.anyRequest().authenticated())
.logout(Customizer.withDefaults()); // clears the remember-me cookie
return http.build();
}go deeper
Know a stolen cookie is the main risk and HTTPS + secure cookies help.
Add persistent tokens for revocation and short validity plus a stable key.
Introduce step-up authentication via fullyAuthenticated and logout/all-devices hygiene.
Frame the convenience-vs-blast-radius trade-off, cluster/key management, theft-detection false positives, and disabling remember-me for high-privilege roles.
Remember-me is fundamentally a **bearer token**: possession equals authentication for the token's lifetime. A principal engineer weighs the convenience against the blast radius of a stolen cookie. **Primary risks.** 1. **Cookie theft / replay** — via network sniffing (no TLS), XSS reading the cookie, malware, or a shared machine. The thief is the user until expiry. 2. **Long validity window** — the default 14 days is a long replay window. 3. **No revocation (TokenBased)** — you can't kill one device; only a password change invalidates, and it invalidates everywhere. 4. **Key mismanagement** — a random/rotating key logs everyone out on restart; a leaked key lets an attacker mint valid TokenBased cookies for any username whose password hash they also know (still needs the hash, but weakens defense in depth). 5. **Privilege escalation via a remembered session** — treating remembered users as fully trusted lets a stolen cookie perform sensitive actions. **Hardening levers.** - **Transport & cookie flags**: enforce HTTPS (HSTS), set the remember-me cookie `Secure` and `HttpOnly`, and add `SameSite=Lax` (or `Strict`) to blunt CSRF/leakage. `HttpOnly` prevents XSS from reading it. - **Strategy choice**: use **PersistentTokenBasedRememberMeServices** so you get token rotation (single-use tokens shrink the replay window), **per-device revocation** (delete the `series` row for 'log out other devices'), and **theft detection** (`CookieTheftException` when a series is reused with a stale token) that both blocks the attacker and alerts the user. - **Short validity**: reduce `tokenValiditySeconds` to match risk appetite (e.g. days, not weeks) for higher-value apps. - **Stable, secret, externalized key**: one fixed `key`, injected via config/secret manager, identical on every node and between `RememberMeServices` and `RememberMeAuthenticationProvider`. Never commit it. - **Step-up authentication**: this is the big one. Remember-me yields a `RememberMeAuthenticationToken`, which `AuthenticationTrustResolver.isRememberMe()` flags and for which the `fullyAuthenticated` expression is **false**. Gate sensitive endpoints with `.access(fullyAuthenticated())` / `@PreAuthorize("isFullyAuthenticated()")` so a remembered user must re-enter their password before changing credentials, email, MFA settings, making payments, or using admin functions. - **Lifecycle hygiene**: clear the cookie on logout (the DSL does this), offer an explicit 'sign out of all devices' that purges the user's `persistent_logins` rows, and consider **disabling remember-me entirely for admin/high-privilege roles**. - **Clustering**: the `PersistentTokenRepository` must be shared (a common DB or distributed store); token rotation under concurrent requests can cause false theft positives, so account for prefetch/parallel tabs and lost `Set-Cookie` responses. - **Auditing**: log/emit events (e.g. on `InteractiveAuthenticationSuccessEvent` and `CookieTheftException`) so remembered logins and suspected thefts are observable. **Decision framing.** For a consumer app, persistent tokens + HTTPS + `Secure/HttpOnly/SameSite` + `fullyAuthenticated` step-up + modest validity is a solid baseline. For genuinely high-assurance systems (banking, admin consoles), consider not offering remember-me at all, or binding it to device fingerprints and short lifetimes with mandatory re-auth for anything sensitive. The unifying principle: **remember-me establishes identity for convenience, not authorization for sensitive operations** — always re-verify for those.
- Why isn't 'the user is authenticated via remember-me' good enough for a password-change endpoint?A stolen cookie authenticates the attacker just like the user. Requiring fullyAuthenticated forces a fresh password entry, which the attacker (who has only the cookie) can't provide, so sensitive actions stay protected even if the cookie leaks.
- What's the advantage of the persistent strategy specifically for incident response?You can revoke a single compromised device by deleting its series row, and cloned-cookie reuse triggers CookieTheftException, which both blocks the attacker and signals that a theft likely occurred — neither is possible with the stateless TokenBased strategy.
saying these in an interview costs you the question
- Treating a remember-me user as fully authenticated for sensitive operations
- Serving remember-me cookies over HTTP or without HttpOnly
- Defaulting to 14-day validity for a high-value app without thought
- Assuming TokenBased offers per-device revocation or theft detection
- Committing the remember-me key or letting it be randomly regenerated per node