spring-projects/spring-security · warning · InvalidCookieException

Cookie token did not contain 2 tokens, but contained '[cooki

Error message

Cookie token did not contain 2 tokens, but contained '[cookieTokens]'

What it means

PersistentTokenBasedRememberMeServices.processAutoLoginCookie expects the decoded remember-me cookie to contain exactly two tokens: the series id and the token value. A cookie yielding any other number of tokens is rejected with InvalidCookieException because its structure is invalid.

Source

Thrown at web/src/main/java/org/springframework/security/web/authentication/rememberme/PersistentTokenBasedRememberMeServices.java:99

	}

	/**
	 * Locates the presented cookie data in the token repository, using the series id. If
	 * the data compares successfully with that in the persistent store, a new token is
	 * generated and stored with the same series. The corresponding cookie value is set on
	 * the response.
	 * @param cookieTokens the series and token values
	 * @throws RememberMeAuthenticationException if there is no stored token corresponding
	 * to the submitted cookie, or if the token in the persistent store has expired.
	 * @throws InvalidCookieException if the cookie doesn't have two tokens as expected.
	 * @throws CookieTheftException if a presented series value is found, but the stored
	 * token is different from the one presented.
	 */
	@Override
	protected UserDetails processAutoLoginCookie(String[] cookieTokens, HttpServletRequest request,
			HttpServletResponse response) {
		if (cookieTokens.length != 2) {
			throw new InvalidCookieException("Cookie token did not contain " + 2 + " tokens, but contained '"
					+ Arrays.asList(cookieTokens) + "'");
		}
		String presentedSeries = cookieTokens[0];
		String presentedToken = cookieTokens[1];
		PersistentRememberMeToken token = this.tokenRepository.getTokenForSeries(presentedSeries);
		if (token == null) {
			// No series match, so we can't authenticate using this cookie
			throw new RememberMeAuthenticationException("No persistent token found for series id: " + presentedSeries);
		}
		// We have a match for this user/series combination
		if (!presentedToken.equals(token.getTokenValue())) {
			// Token doesn't match series value. Delete all logins for this user and throw
			// an exception to warn them.
			this.tokenRepository.removeUserTokens(token.getUsername());
			throw new CookieTheftException(this.messages.getMessage(
					"PersistentTokenBasedRememberMeServices.cookieStolen",
					"Invalid remember-me token (Series/token) mismatch. Implies previous cookie theft attack."));
		}

View on GitHub (pinned to 96852e8860)

Solutions

  1. Clear the stale cookie (cancelCookie happens automatically) and log in again so a fresh, well-formed cookie is issued.
  2. Ensure usernames and token values never contain the ':' delimiter; sanitize or restrict usernames at registration.
  3. Do not override encodeCookie/decodeCookie in ways that change the token count.
  4. If migrating from another remember-me format, invalidate all existing cookies (change the key) so old cookies are rejected cleanly.

Example fix

// before
// username "alice:admin" -> cookie decodes to ["alice","admin",token] -> 3 tokens
usernameValidator.validateUsername("alice:admin"); // not enforced
// after
Assert.isTrue(!username.contains(":"), "username must not contain ':'"); // keep cookie 2-token format
Defensive patterns

Strategy: try-catch

Validate before calling

String plain = new String(Base64.getDecoder().decode(cookieValue), StandardCharsets.UTF_8);
if (plain.split(":", -1).length != 2) {
    // malformed remember-me cookie: cancel it
}

Try / catch

try {
    Authentication a = rememberMeServices.autoLogin(request, response);
} catch (InvalidCookieException e) {
    ((AbstractRememberMeServices) rememberMeServices).cancelCookie(request, response);
}

Prevention

When it happens

Trigger: autoLogin -> processAutoLoginCookie receiving a cookieTokens array whose length != 2 — caused by a corrupted cookie, a cookie whose embedded values contain the ':' delimiter (which is also the token separator), or extra/missing fields from a custom encodeCookie override.

Common situations: Usernames containing ':' splitting into three tokens after decode; old-format cookies from a different remember-me implementation after a migration; manual cookie editing; decoding producing extra elements due to unescaped delimiters.

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/22b32e7517218a61. Report an issue: GitHub.