spring-projects/spring-security · error · BadCredentialsException

The presented AnonymousAuthenticationToken does not contain

Error message

The presented AnonymousAuthenticationToken does not contain the expected key

What it means

AnonymousAuthenticationProvider.authenticate() compares the shared key hash of the incoming AnonymousAuthenticationToken with its configured key. On mismatch it throws BadCredentialsException 'The presented AnonymousAuthenticationToken does not contain the expected key'. The shared-key protects against forged anonymous tokens.

Source

Thrown at core/src/main/java/org/springframework/security/authentication/AnonymousAuthenticationProvider.java:55

 */
public class AnonymousAuthenticationProvider implements AuthenticationProvider, MessageSourceAware {

	protected MessageSourceAccessor messages = SpringSecurityMessageSource.getAccessor();

	private String key;

	public AnonymousAuthenticationProvider(String key) {
		Assert.hasLength(key, "A Key is required");
		this.key = key;
	}

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

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

	@Override
	public void setMessageSource(MessageSource messageSource) {
		Assert.notNull(messageSource, "messageSource cannot be null");
		this.messages = new MessageSourceAccessor(messageSource);
	}

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

View on GitHub (pinned to 96852e8860)

Solutions

  1. Use the same key for AnonymousAuthenticationFilter and AnonymousAuthenticationProvider
  2. If you don't need a custom key, use the same constant/SecureRandom-generated key shared between both beans
  3. Clear old sessions after rotating the key so stale tokens are dropped
  4. Ensure all cluster nodes share the same configured key

Example fix

// before
new AnonymousAuthenticationFilter("uniqueKey", "anon", authorities);
new AnonymousAuthenticationProvider("differentKey");
// after
String key = "uniqueKey";
new AnonymousAuthenticationFilter(key, "anon", authorities);
new AnonymousAuthenticationProvider(key);
Defensive patterns

Strategy: validation

Validate before calling

AnonymousAuthenticationFilter filter = new AnonymousAuthenticationFilter(key, "anonUser", authorities);
AnonymousAuthenticationProvider provider = new AnonymousAuthenticationProvider(key);
assert key != null && !key.isBlank();

Type guard

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

Try / catch

try { return provider.authenticate(auth); } catch (BadCredentialsException e) { log.warn("Anonymous token key mismatch, dropping token"); return null; }

Prevention

When it happens

Trigger: An AnonymousAuthenticationToken was created with a different key string than the one configured on AnonymousAuthenticationProvider (via AnonymousAuthenticationFilter).

Common situations: Changing the anonymous key in the filter but not the provider (or vice versa); multiple app nodes with different configured keys; tokens deserialized from an old session after key rotation; copying example code with mismatched keys.

Understand the failure class

Related errors


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