apereo/cas · error · FailedLoginException
Unknown Duo Security authentication attempt
Error message
Unknown Duo Security authentication attempt
What it means
FailedLoginException thrown by DuoSecurityAuthenticationHandler.doAuthentication() when the presented credential is neither a DuoSecurityUniversalPromptCredential nor a DuoSecurityDirectCredential. The handler switches over the credential type and the default branch has no supported path, so it declares the authentication attempt unknown and fails it.
Solutions
- Ensure the flow creates and submits the correct credential: DuoSecurityUniversalPromptCredential for the Universal Prompt, or DuoSecurityDirectCredential (e.g. DuoSecurityPasscodeCredential) for direct/API mode.
- Review custom webflow actions/configurations that build credentials for the MFA hop and align them with the current CAS Duo credential classes.
- Check that only the intended Duo authentication handler handles this credential (authentication policy/selector misrouting another credential type into Duo).
Example fix
// before val credential = new UsernamePasswordCredential(username, pass); // after val credential = new DuoSecurityDirectCredential(username, passcode);
Defensive patterns
Strategy: type-guard
Validate before calling
// Before invoking the handler, ensure credential type
if (!(credential instanceof DuoSecurityUniversalPromptCredential)
&& !(credential instanceof DuoSecurityDirectCredential)) {
throw new IllegalArgumentException("Unsupported credential for Duo: " + credential.getClass());
} Type guard
boolean isDuoCredential(Credential c) {
return c instanceof DuoSecurityUniversalPromptCredential || c instanceof DuoSecurityDirectCredential;
} Try / catch
try {
result = duoHandler.authenticate(credential);
} catch (FailedLoginException e) {
LOGGER.error("Duo credential type unsupported: {}", credential.getClass(), e);
} Prevention
- Build MFA flow credentials from the current CAS Duo credential classes only.
- After CAS upgrades, re-check custom webflow code that constructs Duo credentials.
- Scope Duo handler registration so only Duo credentials route to it.
When it happens
Trigger: Invoking the Duo handler with any other Credential implementation — e.g. a plain UsernamePasswordCredential routed to the Duo MFA handler, a custom credential class, or a credential that lost its type after serialization/custom flow code.
Common situations: See trigger scenarios.
Understand the failure class
Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
- Unable to determine google authenticator token credential
- State [ : : ] does not have a matching transition for
- Invalid response format received from Duo
- Duo returned code
- Duo Security passcode authentication has failed
AI-assisted analysis of apereo/cas@e7288fc434 (2026-09-08).
Data as JSON: /api/errors/b93d61cddf8ae0f1.
Report an issue: GitHub.
Appendix: source
Thrown at support/cas-server-support-duo-core/src/main/java/org/apereo/cas/adaptors/duo/authn/DuoSecurityAuthenticationHandler.java:81
* @return the result of this handler
* @throws GeneralSecurityException general security exception for errors
*/
@Override
protected AuthenticationHandlerExecutionResult doAuthentication(final Credential credential, final Service service) throws Exception {
return switch (credential) {
case final DuoSecurityPasscodeCredential duo -> {
LOGGER.debug("Attempting to authenticate credential via Duo Security passcode");
yield authenticateDuoPasscodeCredential(duo);
}
case final DuoSecurityUniversalPromptCredential duo -> {
LOGGER.debug("Attempting to authenticate credential via Duo Security universal prompt");
yield authenticateDuoUniversalPromptCredential(duo);
}
case final DuoSecurityDirectCredential duo -> {
LOGGER.debug("Attempting to directly authenticate credential against Duo");
yield authenticateDuoApiCredential(duo);
}
default -> throw new FailedLoginException("Unknown Duo Security authentication attempt");
};
}
/**
* Resolve principal.
*
* @param principal the principal
* @return the principal
*/
protected Principal resolvePrincipal(final Principal principal) {
return multifactorAuthenticationPrincipalResolver
.stream()
.filter(resolver -> resolver.supports(principal))
.findFirst()
.map(resolver -> resolver.resolve(principal))
.orElseThrow(() -> new IllegalStateException("Unable to resolve principal for Duo Security multifactor authentication"));
}
View on GitHub (pinned to e7288fc434)