spring-projects/spring-security · warning · InvalidCookieException
Cookie token[1] has expired (expired on '<expiryDate>'; curr
Error message
Cookie token[1] has expired (expired on '<expiryDate>'; current time is '<now>')
What it means
The second token in the remember-me cookie is the expiry timestamp in epoch millis. TokenBasedRememberMeServices compares it with the current time; if the expiry is in the past it throws InvalidCookieException with both dates. This is the standard expired remember-me cookie condition, forcing a full re-authentication.
Source
Thrown at web/src/main/java/org/springframework/security/web/authentication/rememberme/TokenBasedRememberMeServices.java:134
* @since 5.8
*/
public TokenBasedRememberMeServices(String key, UserDetailsService userDetailsService,
RememberMeTokenAlgorithm encodingAlgorithm) {
super(key, userDetailsService);
Assert.notNull(encodingAlgorithm, "encodingAlgorithm cannot be null");
this.encodingAlgorithm = encodingAlgorithm;
}
@Override
protected UserDetails processAutoLoginCookie(String[] cookieTokens, HttpServletRequest request,
HttpServletResponse response) {
if (!isValidCookieTokensLength(cookieTokens)) {
throw new InvalidCookieException(
"Cookie token did not contain 3 or 4 tokens, but contained '" + Arrays.asList(cookieTokens) + "'");
}
long tokenExpiryTime = getTokenExpiryTime(cookieTokens);
if (isTokenExpired(tokenExpiryTime)) {
throw new InvalidCookieException("Cookie token[1] has expired (expired on '" + new Date(tokenExpiryTime)
+ "'; current time is '" + new Date() + "')");
}
// Check the user exists. Defer lookup until after expiry time checked, to
// possibly avoid expensive database call.
UserDetails userDetails = getUserDetailsService().loadUserByUsername(cookieTokens[0]);
Assert.notNull(userDetails, () -> "UserDetailsService " + getUserDetailsService()
+ " returned null for username " + cookieTokens[0] + ". " + "This is an interface contract violation");
// Check signature of token matches remaining details. Must do this after user
// lookup, as we need the DAO-derived password. If efficiency was a major issue,
// just add in a UserCache implementation, but recall that this method is usually
// only called once per HttpSession - if the token is valid, it will cause
// SecurityContextHolder population, whilst if invalid, will cause the cookie to
// be cancelled.
String actualTokenSignature = cookieTokens[2];
RememberMeTokenAlgorithm actualAlgorithm = this.matchingAlgorithm;
// If the cookie value contains the algorithm, we use that algorithm to check the
// signature
if (cookieTokens.length == 4) {View on GitHub (pinned to 96852e8860)
Solutions
- Have the user log in again — expected behavior for expired cookies
- Increase tokenValiditySeconds in the rememberMe() configuration if sessions expire too soon
- Verify all servers (and DB time if applicable) use NTP-synced clocks
- Remember expiry is absolute from login, not sliding; use persistent tokens if sliding sessions are needed
Example fix
// before
http.rememberMe(r -> r.key("secret")); // default 14 days
// after
http.rememberMe(r -> r.key("secret").tokenValiditySeconds(60 * 60 * 24 * 30)); // 30 days Defensive patterns
Strategy: try-catch
Validate before calling
long expiry = Long.parseLong(parts[1]);
if (expiry <= System.currentTimeMillis()) {
// cookie already expired client-side; go straight to login
response.sendRedirect("/login");
return;
} Type guard
boolean isRememberMeCookieExpired(String[] cookieTokens) {
return Long.parseLong(cookieTokens[1]) <= System.currentTimeMillis();
} Try / catch
try {
UserDetails u = rememberMeServices.autoLogin(request, response);
} catch (InvalidCookieException e) {
if (e.getMessage().contains("has expired")) {
response.sendRedirect("/login?expired=true");
return;
}
throw e;
} Prevention
- Set tokenValiditySeconds appropriate to user expectations
- Keep server clocks NTP-synced in clusters
- Redirect to login with an 'expired' hint for better UX
- Use persistent tokens if you need longer-lived auto-login
When it happens
Trigger: processAutoLoginCookie decodes a cookie whose tokenValiditySeconds window (default 14 days) has elapsed — isTokenExpired(tokenExpiryTime) returns true and the cookie is rejected.
Common situations: User returns after the configured tokenValiditySeconds period; server clock skew between nodes making cookies appear expired; very short validity configured while expecting longer sessions; expired cookie kept by browser and replayed.
Related errors
- Cookie token was not Base64 encoded; value was '<cookieValue
- Cookie token did not contain 2 tokens, but contained '[cooki
- Cookie token did not contain 3 or 4 tokens, but contained '[
- Cookie token[1] did not contain a valid number (contained '"
- Can not set rememberMeCookieName and custom rememberMeServic
AI-assisted analysis of spring-projects/spring-security@96852e8860 (2026-09-10).
Data as JSON: /api/errors/4a180e7b5ef2f7e9.
Report an issue: GitHub.