apereo/cas · error · FailedLoginException
Failed to authenticate code
Error message
Failed to authenticate code
What it means
GoogleAuthenticatorConfirmAccountRegistrationAction requires the user to submit a valid OTP during the confirm-registration webflow step to prove device possession. When validator.validate returns null (the token fails authorization) it throws FailedLoginException 'Failed to authenticate code <token>'. Registration of the GAuth account therefore cannot be confirmed.
Solutions
- Re-enter a freshly generated OTP from the newly enrolled authenticator entry
- Verify the QR scan produced the correct secret (re-register the account to get a new QR)
- Check CAS server time synchronization (NTP)
- Confirm the same account being verified is the one whose secret matches the code
Defensive patterns
Strategy: try-catch
Validate before calling
// client: only submit fresh 6-digit codes
if (!/^\d{6}$/.test(token)) throw new IllegalArgumentException("Enter the 6-digit code from the app"); Try / catch
try {
action.executeInternal(rc);
} catch (FailedLoginException e) {
return error("Registration could not be confirmed: enter a new code from your authenticator");
} Prevention
- Have users confirm the QR belongs to the account being registered
- Keep server time NTP-synced
- Generate a fresh code after each failed confirmation attempt
- Re-scan the QR if failures persist (secret mismatch)
When it happens
Trigger: doExecuteInternal receives a token on the confirm-account-registration flow, calls validator.validate(token, authentication) and validatedToken is null — wrong code, reused code, clock drift, or account/secret mismatch — triggering the FailedLoginException before accountRegistrationVerified is called.
Common situations: User mistypes the code shown during registration; code comes from a different app entry; server clock skew; user retries an OTP already consumed by a prior validation.
Understand the failure class
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
- Failed to authenticate code
- Failed to authenticate code
- Failed to authenticate code
- cannot be found in the registry
- cannot reuse OTP
AI-assisted analysis of apereo/cas@e7288fc434 (2026-09-08).
Data as JSON: /api/errors/ec16acbecef7a560.
Report an issue: GitHub.
Appendix: source
Thrown at support/cas-server-support-gauth-core/src/main/java/org/apereo/cas/gauth/web/flow/GoogleAuthenticatorConfirmAccountRegistrationAction.java:59
val requestParameters = requestContext.getRequestParameters();
val accountId = requestParameters.getRequired(OneTimeTokenAccountConfirmSelectionRegistrationAction.REQUEST_PARAMETER_ACCOUNT_ID, Long.class);
val validate = requestParameters.getBoolean(OneTimeTokenAccountSaveRegistrationAction.REQUEST_PARAMETER_VALIDATE);
val account = repository.get(accountId);
Objects.requireNonNull(account, "Account cannot be null");
if (BooleanUtils.isTrue(validate)) {
val token = requestParameters.getRequired(GoogleAuthenticatorSaveRegistrationAction.REQUEST_PARAMETER_TOKEN, String.class);
val authentication = WebUtils.getAuthentication(requestContext);
val principal = authentication.getPrincipal().getId();
LOGGER.debug("Validating account [{}] with token [{}] for principal [{}]", accountId, token, principal);
val tokenCredential = new GoogleAuthenticatorTokenCredential(token, accountId);
val validatedToken = validator.validate(authentication, tokenCredential);
if (validatedToken != null) {
LOGGER.debug("Validated OTP token [{}] successfully for [{}]", validatedToken, principal);
accountRegistrationVerified(requestContext, account);
return success();
}
LOGGER.warn("Authorization of OTP token [{}] has failed", token);
throw new FailedLoginException("Failed to authenticate code " + token);
}
if (!isAccountRegistrationVerified(requestContext, account)) {
LOGGER.warn("Account registration is not verified for [{}]", account.getId());
throw new FailedLoginException("Unauthorized account registration attempt for id " + account.getId());
}
accountRegistrationUnverified(requestContext, account);
return success();
}
protected void accountRegistrationVerified(final RequestContext requestContext, final OneTimeTokenAccount account) {
account.getProperties().add(ACCOUNT_PROPERTY_REGISTRATION_VERIFIED);
repository.update(account);
}
protected void accountRegistrationUnverified(final RequestContext requestContext, final OneTimeTokenAccount account) {
account.getProperties().remove(ACCOUNT_PROPERTY_REGISTRATION_VERIFIED);View on GitHub (pinned to e7288fc434)