apereo/cas · error · FailedLoginException
Failed to authenticate code
Error message
Failed to authenticate code
What it means
GoogleAuthenticatorDeleteAccountAction requires OTP re-verification before removing a GAuth account. When the submitted token fails validation (validator.validate returns null) it throws FailedLoginException 'Failed to authenticate code <token>', aborting the delete flow so an attacker cannot remove a device without proving possession.
Solutions
- Submit a fresh OTP generated by the authenticator entry bound to the account being deleted
- Verify the correct account is selected in the flow (multiple accounts need the right entry's code)
- Check server time sync if codes are consistently rejected
- Re-register the device if its secret no longer matches the stored account
Defensive patterns
Strategy: try-catch
Validate before calling
if (token == null || !/^\d{6}$/.test(token)) return error("Enter the current 6-digit code to confirm removal"); Try / catch
try {
action.executeInternal(rc);
} catch (FailedLoginException e) {
return error("Deletion not confirmed: enter a valid OTP for this account");
} Prevention
- Ensure the user uses the authenticator entry tied to the account being deleted
- Keep server time synced
- Request a fresh code after each failed attempt
- Verify stored account secret still matches the device
When it happens
Trigger: doExecuteInternal receives a token for the delete-account flow, calls validator.validate(token, authentication); validatedToken is null (wrong/reused/expired code, secret mismatch) so the exception is thrown before accountRemovalVerified is called.
Common situations: User enters a code from the wrong authenticator entry while trying to remove the account; code already consumed; clock drift; mistyped code.
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/e43e72a75e573586.
Report an issue: GitHub.
Appendix: source
Thrown at support/cas-server-support-gauth-core/src/main/java/org/apereo/cas/gauth/web/flow/GoogleAuthenticatorDeleteAccountAction.java:58
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);
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);
accountRemovalVerified(requestContext, account);
return success();
}
LOGGER.warn("Authorization of OTP token [{}] has failed", token);
throw new FailedLoginException("Failed to authenticate code " + token);
}
if (!isAccountRemovalVerified(requestContext, account)) {
LOGGER.warn("Account removal is not verified for [{}]", account.getId());
throw new FailedLoginException("Unauthorized account removal attempt " + account.getId());
}
LOGGER.debug("Deleting account [{}]", account.getId());
repository.delete(account.getId());
return success();
}
protected void accountRemovalVerified(final RequestContext requestContext, final OneTimeTokenAccount account) {
account.getProperties().add(ACCOUNT_PROPERTY_REMOVAL_VERIFIED);
repository.update(account);
}
protected boolean isAccountRemovalVerified(final RequestContext requestContext, final OneTimeTokenAccount account) {View on GitHub (pinned to e7288fc434)