apereo/cas · error · FailedLoginException
Duo Security authentication has failed
Error message
Duo Security authentication has failed
What it means
Duo Security's Authentication API rejected the authentication attempt or the API call failed. DuoSecurityAuthenticationHandler.authenticateDuoApiCredential catches all exceptions (logging them) and then unconditionally throws FailedLoginException, so any Duo API/network/config failure surfaces as this generic failure message. It means CAS could not produce a successful Duo authentication result for the credential.
Solutions
- Check the server log just above the exception: LoggingUtils.error(LOGGER, e) records the real root cause (network, signature, or API error) and fix that first
- Verify cas.authn.duo.[name].duoIntegrationKey, secretKey and apiHostname match the Duo Admin Console protection values
- Confirm the CAS server can reach https://<api-host>.duosecurity.com (curl test; check proxies/firewalls/TLS trust)
- Ensure the user is enrolled in the Duo application and the account is not locked/bypass-expired
Example fix
// before (properties) cas.authn.duo.duo-api-host=api-wrong-host.duosecurity.com // after cas.authn.duo.duo-api-host=api-XXXXXXXX.duosecurity.com
Defensive patterns
Strategy: try-catch
Validate before calling
// before calling authentication, verify config
if (duoProps.getApiHostname() == null || duoProps.getSecretKey() == null || duoProps.getDuoIntegrationKey() == null)
throw new IllegalStateException("Duo integration keys/apiHostname must be configured"); Try / catch
try {
handlerResult = doAuthentication(credential);
} catch (FailedLoginException e) {
LOGGER.error("Duo auth failed; inspect earlier LoggingUtils stack trace for root cause", e);
return redirectToDuoErrorScreen(e);
} Prevention
- Log/inspect the swallowed root-cause exception logged by LoggingUtils before this error
- Test outbound HTTPS to the Duo API host from the CAS server during deployment
- Keep Duo Admin Console integration values and CAS properties in sync
- Enroll test users before rollout to catch enrollment issues early
When it happens
Trigger: doAuthentication calls the Duo auth API and either the signed response cannot be verified, the Duo service returns an error (invalid integration key/secret, expired license, blocked user), the network call fails/times out, or the returned payload yields no principal — the catch block swallows the cause and rethrows this FailedLoginException.
Common situations: Wrong duoIntegrationKey/secretKey/apiHostname in cas.authn.duo properties; Duo Admin Console not registering the CAS host; firewall/proxy blocking outbound HTTPS to api-*.duosecurity.com; clock skew breaking signed response validation; user not enrolled in Duo.
Understand the failure class
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
- Unable to extract credentials for multifactor authentication
- Invalid response format received from Duo
- Duo returned code
- Unknown Duo Security authentication attempt
- Duo Security passcode authentication has failed
AI-assisted analysis of apereo/cas@e7288fc434 (2026-09-08).
Data as JSON: /api/errors/2f692a8de4a25044.
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:142
} catch (final Throwable e) {
LoggingUtils.error(LOGGER, e);
}
throw new FailedLoginException("Duo Security universal prompt authentication has failed");
}
private AuthenticationHandlerExecutionResult authenticateDuoApiCredential(
final DuoSecurityDirectCredential credential) throws FailedLoginException {
try {
val duoAuthenticationService = multifactorAuthenticationProvider.getObject().getDuoAuthenticationService();
if (duoAuthenticationService.authenticate(credential).isSuccess()) {
val principal = resolvePrincipal(credential.getPrincipal());
LOGGER.debug("Duo Security has successfully authenticated [{}]", principal.getId());
return createHandlerResult(credential, principal, new ArrayList<>());
}
} catch (final Exception e) {
LoggingUtils.error(LOGGER, e);
}
throw new FailedLoginException("Duo Security authentication has failed");
}
}
View on GitHub (pinned to e7288fc434)