spring-projects/spring-security · error · BadCredentialsException

The presented RememberMeAuthenticationToken does not contain

Error message

The presented RememberMeAuthenticationToken does not contain the expected key

What it means

RememberMeAuthenticationProvider.authenticate() compares the key hash of the incoming RememberMeAuthenticationToken with its configured key. On mismatch it throws BadCredentialsException 'The presented RememberMeAuthenticationToken does not contain the expected key'. The shared key validates that the token was issued by the matching remember-me services.

Source

Thrown at core/src/main/java/org/springframework/security/authentication/RememberMeAuthenticationProvider.java:59

	private String key;

	public RememberMeAuthenticationProvider(String key) {
		Assert.hasLength(key, "key must have a length");
		this.key = key;
	}

	@Override
	public void afterPropertiesSet() {
		Assert.notNull(this.messages, "A message source must be set");
	}

	@Override
	public @Nullable Authentication authenticate(Authentication authentication) throws AuthenticationException {
		if (!supports(authentication.getClass())) {
			return null;
		}
		if (this.key.hashCode() != ((RememberMeAuthenticationToken) authentication).getKeyHash()) {
			throw new BadCredentialsException(this.messages.getMessage("RememberMeAuthenticationProvider.incorrectKey",
					"The presented RememberMeAuthenticationToken does not contain the expected key"));
		}
		return authentication;
	}

	public String getKey() {
		return this.key;
	}

	@Override
	public void setMessageSource(MessageSource messageSource) {
		this.messages = new MessageSourceAccessor(messageSource);
	}

	@Override
	public boolean supports(Class<?> authentication) {
		return (RememberMeAuthenticationToken.class.isAssignableFrom(authentication));
	}

View on GitHub (pinned to 96852e8860)

Solutions

  1. Configure the identical key on RememberMeServices and RememberMeAuthenticationProvider
  2. If the key was rotated, have users log in again / invalidate old remember-me cookies
  3. Ensure consistent key across all nodes in a cluster
  4. In multi-filter-chain setups, make sure each chain's provider matches its own services' key

Example fix

// before
TokenBasedRememberMeServices services = new TokenBasedRememberMeServices("keyOne", uds);
new RememberMeAuthenticationProvider("keyTwo");
// after
String key = "keyOne";
TokenBasedRememberMeServices services = new TokenBasedRememberMeServices(key, uds);
new RememberMeAuthenticationProvider(key);
Defensive patterns

Strategy: validation

Validate before calling

RememberMeAuthenticationProvider provider = new RememberMeAuthenticationProvider(key);
TokenBasedRememberMeServices services = new TokenBasedRememberMeServices(key, uds);
assert key != null && !key.isBlank();

Type guard

boolean hasValidKey(RememberMeAuthenticationToken t, String key) { return key != null && key.hashCode() == t.getKeyHash(); }

Try / catch

try { return provider.authenticate(auth); } catch (BadCredentialsException e) { log.warn("Remember-me token key mismatch, forcing re-login"); return null; }

Prevention

When it happens

Trigger: A RememberMeAuthenticationToken created with key A reaches a RememberMeAuthenticationProvider configured with key B — typically RememberMeServices and the provider keys differ.

Common situations: TokenBasedRememberMeServices key differs from provider key; key changed after tokens were persisted in cookies/sessions; multiple security filter chains with different remember-me keys; cluster nodes with different key config.

Understand the failure class

Related errors


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