apereo/cas · error · MultifactorAuthenticationFailedException
Failed to authenticate code
Error message
Failed to authenticate code
What it means
CasSimpleMultifactorAuthenticationHandler.doAuthentication validates the MFA token credential against the simple MFA service and then compares the token's principal with the currently active authentication principal. On any validation failure or mismatch, it throws MultifactorAuthenticationFailedException "Failed to authenticate code <id>". It means the supplied one-time MFA code/ticket is not usable for this authentication attempt.
Solutions
- Request and submit a fresh MFA code within its validity window in the same session
- Ensure the same authenticated principal completes the MFA step (no account switch mid-flow)
- Verify all CAS nodes share the same ticket registry so tokens issued on one node validate on another
- Check throttling configuration/bucket limits if users are being locked out by retry volume
Defensive patterns
Strategy: retry
Try / catch
try {
handlerResult = authenticationHandler.authenticate(transaction);
} catch (MultifactorAuthenticationFailedException e) {
// discard the stale/foreign code and re-enter the MFA flow to get a fresh one
mfaRelayService.requestNewCode(activePrincipal);
} Prevention
- Submit MFA codes promptly; they are one-time and short-lived
- Complete the whole login (primary + MFA) in one session and browser
- Ensure clustered CAS nodes share one ticket registry (e.g. Redis/Hazelcast)
When it happens
Trigger: doAuthentication -> multifactorAuthenticationService.validate(...) throwing (missing principal on ticket, principal mismatch, throttled attempts) or the returned principal not equaling findActivePrincipal(), e.g. the code was issued to a different user or was already consumed/expired.
Common situations: User submits an expired or already-used MFA code; code generated in one browser/session but submitted from another login (principal mismatch); clustered deployments where the ticket registry is not shared so the token cannot be found; throttling after repeated wrong codes.
Understand the failure class
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
- Credential principal
- Principal assigned to token
- Unable to extract credentials for multifactor authentication
- Duo Security authentication has failed
- Cannot validate authentication for: [login]
AI-assisted analysis of apereo/cas@e7288fc434 (2026-09-08).
Data as JSON: /api/errors/934fb319bc348f92.
Report an issue: GitHub.
Appendix: source
Thrown at support/cas-server-support-simple-mfa-core/src/main/java/org/apereo/cas/mfa/simple/CasSimpleMultifactorAuthenticationHandler.java:75
@Override
public boolean supports(final Class<? extends Credential> clazz) {
return CasSimpleMultifactorTokenCredential.class.isAssignableFrom(clazz);
}
@Override
protected AuthenticationHandlerExecutionResult doAuthentication(final Credential credential,
final Service service) throws Exception {
return FunctionUtils.doAndThrow(() -> {
val tokenCredential = (CasSimpleMultifactorTokenCredential) credential;
val credentialPrincipal = multifactorAuthenticationService.fetch(tokenCredential);
val resolvedPrincipal = resolvePrincipal(applicationContext, credentialPrincipal);
val principal = multifactorAuthenticationService.validate(resolvedPrincipal, tokenCredential);
val activePrincipal = findActivePrincipal();
if (!principal.equals(activePrincipal)) {
LOGGER.warn("Credential principal [{}] does not match authentication principal [{}]",
principal.getId(), activePrincipal.getId());
throw new MultifactorAuthenticationFailedException("Failed to authenticate code " + tokenCredential.getId());
}
return createHandlerResult(tokenCredential, principal);
}, MultifactorAuthenticationFailedException::new);
}
protected Principal findActivePrincipal() {
val authentication = Objects.requireNonNull(WebUtils.getInProgressAuthentication());
val principal = authentication.getPrincipal();
return principal.getOwner();
}
}
View on GitHub (pinned to e7288fc434)