spring-projects/spring-security · error · InvalidCookieException

Cookie token[1] did not contain a valid number (contained '"

Error message

Cookie token[1] did not contain a valid number (contained '" + cookieTokens[1] + "')

What it means

The second token in the remember-me cookie must parse as a long (epoch millis expiry). getTokenExpiryTime wraps Long.valueOf(cookieTokens[1]) and converts any NumberFormatException into InvalidCookieException reporting the offending value. It means the cookie is malformed at the expiry position.

Source

Thrown at web/src/main/java/org/springframework/security/web/authentication/rememberme/TokenBasedRememberMeServices.java:174

		String expectedTokenSignature = makeTokenSignature(tokenExpiryTime, userDetails.getUsername(),
				userDetails.getPassword(), actualAlgorithm);
		if (!equals(expectedTokenSignature, actualTokenSignature)) {
			throw new InvalidCookieException("Cookie contained signature '" + actualTokenSignature + "' but expected '"
					+ expectedTokenSignature + "'");
		}
		return userDetails;
	}

	private boolean isValidCookieTokensLength(String[] cookieTokens) {
		return cookieTokens.length == 3 || cookieTokens.length == 4;
	}

	private long getTokenExpiryTime(String[] cookieTokens) {
		try {
			return Long.valueOf(cookieTokens[1]);
		}
		catch (NumberFormatException nfe) {
			throw new InvalidCookieException(
					"Cookie token[1] did not contain a valid number (contained '" + cookieTokens[1] + "')");
		}
	}

	/**
	 * Calculates the digital signature to be put in the cookie. Default value is
	 * {@link #encodingAlgorithm} applied to ("username:tokenExpiryTime:password:key")
	 */
	protected String makeTokenSignature(long tokenExpiryTime, String username, String password) {
		String data = username + ":" + tokenExpiryTime + ":" + password + ":" + getKey();
		try {
			MessageDigest digest = MessageDigest.getInstance(this.encodingAlgorithm.getDigestAlgorithm());
			return new String(Hex.encode(digest.digest(data.getBytes())));
		}
		catch (NoSuchAlgorithmException ex) {
			throw new IllegalStateException("No " + this.encodingAlgorithm.name() + " algorithm available!");
		}
	}

View on GitHub (pinned to 96852e8860)

Solutions

  1. Clear the cookie and log in again
  2. Ensure no two apps on the same domain use the same remember-me cookie name
  3. Verify intermediaries are not truncating or rewriting the Cookie header
  4. After format upgrades, clear legacy cookies

Example fix

// before (colliding cookie names on shared domain)
http.rememberMe(r -> r.key("k"));
// after
http.rememberMe(r -> r.key("k").cookieName("myapp-remember-me"));
Defensive patterns

Strategy: try-catch

Validate before calling

String[] parts = cookieValue.split(":");
if (parts.length < 2 || !parts[1].matches("\\d+")) {
    deleteRememberMeCookie(response);
    return;
}

Type guard

boolean hasNumericExpiry(String[] cookieTokens) {
    return cookieTokens.length >= 2 && cookieTokens[1].matches("\\d+");
}

Try / catch

try {
    UserDetails u = rememberMeServices.autoLogin(request, response);
} catch (InvalidCookieException e) {
    cookieClearingLogoutHandler.logout(request, response, null);
    response.sendRedirect("/login");
}

Prevention

When it happens

Trigger: processAutoLoginCookie calls getTokenExpiryTime with a cookie whose second colon-separated token is non-numeric — corrupted cookie, truncation, wrong delimiter, or a cookie produced by an incompatible format.

Common situations: Cookie mangled by proxies or browser extensions; apps sharing cookie name with different formats; manual editing or debugging of cookies; partial cookie writes.

Understand the failure class

Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.

Related errors


AI-assisted analysis of spring-projects/spring-security@96852e8860 (2026-09-10). Data as JSON: /api/errors/d10c9c6a98775518. Report an issue: GitHub.