apereo/cas · warning · FailedLoginException
Authorization of OTP token
Error message
Authorization of OTP token [{}] has failed What it means
GoogleAuthenticatorDeleteAccountAction validates the OTP token supplied when removing a device. If validator.validate returns null the removal request is rejected: this warning is logged and FailedLoginException is thrown, so the account is not deleted.
Solutions
- Ask the user to submit a fresh code from the authenticator entry corresponding to the device being deleted
- Verify the accountId/registrationId selection matches the account whose token is submitted
- Check clock sync and validation window settings if all valid codes are rejected
- If the account secret in the repository is corrupted, re-register the device before removal
Defensive patterns
Strategy: retry
Validate before calling
boolean codeLooksValid = code != null && code.matches("\\d{6}");
// and confirm the selected device id matches the code source Try / catch
try {
event = deleteAccountAction.execute(requestContext);
} catch (FailedLoginException e) {
// prompt for a fresh code bound to the device being removed
} Prevention
- Use a code from the specific app entry being deleted
- Submit codes promptly after generation
- Keep clocks synchronized
- Re-register the device if its stored secret is suspect
When it happens
Trigger: doExecuteInternal receives a GoogleAuthenticatorTokenCredential for account removal whose token fails validation (wrong code, expired window, reused token, or token not bound to the account being deleted).
Common situations: User confirms device removal with a stale or mistyped code; token already consumed; wrong registrationId selected so codes are validated against the wrong account secret.
Related errors
- Failed to authenticate code
- Failed to authenticate code
- Failed to authenticate code
- Authorization of OTP token
- Account removal is not verified for
AI-assisted analysis of apereo/cas@e7288fc434 (2026-09-08).
Data as JSON: /api/errors/aa24a4819e56b852.
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:57
protected @Nullable Event doExecuteInternal(final RequestContext requestContext) throws Throwable {
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);
}
View on GitHub (pinned to e7288fc434)