spring-projects/spring-security · error · BadCredentialsException
RunAsImplAuthenticationProvider.incorrectKey
RunAsImplAuthenticationProvider.incorrectKey
Error message
The presented RunAsUserToken does not contain the expected key
What it means
RunAsImplAuthenticationProvider validates RunAsUserToken instances by comparing the token's key hash with the provider's configured key. If they do not match, the token is not trusted and BadCredentialsException is thrown. This prevents forged run-as identity escalation.
Source
Thrown at access/src/main/java/org/springframework/security/access/intercept/RunAsImplAuthenticationProvider.java:68
@NullUnmarked
@Deprecated
public class RunAsImplAuthenticationProvider implements InitializingBean, AuthenticationProvider, MessageSourceAware {
protected MessageSourceAccessor messages = SpringSecurityMessageSource.getAccessor();
@SuppressWarnings("NullAway.Init")
private @Nullable String key;
@Override
public void afterPropertiesSet() {
Assert.notNull(this.key, "A Key is required and should match that configured for the RunAsManagerImpl");
}
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
RunAsUserToken token = (RunAsUserToken) authentication;
if (token.getKeyHash() != this.key.hashCode()) {
throw new BadCredentialsException(this.messages.getMessage("RunAsImplAuthenticationProvider.incorrectKey",
"The presented RunAsUserToken does not contain the expected key"));
}
return authentication;
}
public String getKey() {
return this.key;
}
public void setKey(String key) {
this.key = key;
}
@Override
public void setMessageSource(MessageSource messageSource) {
this.messages = new MessageSourceAccessor(messageSource);
}
View on GitHub (pinned to 96852e8860)
Solutions
- Ensure the exact same key string is set on both RunAsManagerImpl and RunAsImplAuthenticationProvider
- Externalize the shared key into a property so both beans reference one value
- Verify the authentication provider handling run-as tokens is registered for RunAsUserToken type
- Check for stale serialized tokens from a previous key and re-authenticate
Example fix
// before
new RunAsManagerImpl("keyOne", "ROLE_RUNAS");
new RunAsImplAuthenticationProvider("keyTwo");
// after
String key = "shared-secure-key";
new RunAsManagerImpl(key, "ROLE_RUNAS");
new RunAsImplAuthenticationProvider(key); Defensive patterns
Strategy: validation
Validate before calling
if (runAsToken instanceof RunAsUserToken t && t.getKeyHash() != sharedKey.hashCode()) {
throw new IllegalStateException("RunAs key mismatch before provider call");
} Type guard
boolean isTrustedRunAsToken(Authentication auth, String key) {
return auth instanceof RunAsUserToken t && t.getKeyHash() == key.hashCode();
} Try / catch
try {
return provider.authenticate(token);
} catch (BadCredentialsException e) {
throw new AuthenticationServiceException("RunAs key mismatch", e);
} Prevention
- Define the run-as key once in shared configuration
- Never change the key without invalidating in-flight tokens
- Verify provider ordering in the AuthenticationManager
When it happens
Trigger: authenticate() is given a RunAsUserToken whose getKeyHash() differs from hashCode() of the RunAsManager's configured secure key — typically the RunAsManager and RunAsImplAuthenticationProvider were configured with different keys.
Common situations: Copy-paste configuration where the run-as key differs between the <run-as-manager>/RunAsManagerImpl and the authentication provider; multiple applications sharing a token cache but keys were changed; bean wiring pulling the wrong provider.
Related errors
- CasAuthenticationProvider.incorrectKey
- Bad credentials
- Failed to authenticate the one-time token
- Bad credentials
- No pre-authenticated principal found in request.
AI-assisted analysis of spring-projects/spring-security@96852e8860 (2026-09-10).
Data as JSON: /api/errors/3952afacfe4aa172.
Report an issue: GitHub.