apereo/cas · warning · FailedLoginException
Account registration is not verified for
Error message
Account registration is not verified for [{}] What it means
After token validation, the confirm-registration action additionally requires that the registration-verified flag was previously stored in the webflow request context. If isAccountRegistrationVerified returns false, the user is attempting to finish registration without having completed the verification step, and a FailedLoginException is thrown.
Solutions
- Restart the MFA account registration flow from the beginning so the token verification step runs before confirmation
- Do not reuse or manually resume old webflow executions; start a fresh login/registration attempt
- If customizing the flow, ensure the state that calls accountRegistrationVerified(...) executes before the confirm action
- Check that the webflow scope holding the verified flag is not cleared (session/flow scope configuration)
Defensive patterns
Strategy: validation
Validate before calling
// before invoking the confirm step, ensure verification happened
// (in custom flow code) check flow scope flag before transitioning to confirm
boolean verified = requestContext.getFlowScope().contains("googleAuthenticatorRegistrationVerified"); Try / catch
try {
event = action.execute(requestContext);
} catch (FailedLoginException e) {
// redirect user to restart the registration flow from the first step
} Prevention
- Never deep-link into later webflow states
- Run states in order: verify token -> confirm registration
- Avoid resuming expired webflow executions
- Keep session/flow scope intact between steps
When it happens
Trigger: doExecuteInternal reaches the guard when no prior successful token verification stored the account (e.g. user jumps directly to the confirm step, replayed flow execution, or flow state was resumed out of order).
Common situations: User bookmarks/back-navigates into the confirmation screen; flow execution id reused or expired; session loss between verification and confirmation steps; customizing the webflow and skipping the verification state.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- Unauthorized account registration attempt for id
- No registration records could be found for
- Authorization of OTP token
- Account removal is not verified for
- Unable to determine google authenticator account
AI-assisted analysis of apereo/cas@e7288fc434 (2026-09-08).
Data as JSON: /api/errors/67a895636c28554d.
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:63
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);
repository.update(account);
}
protected boolean isAccountRegistrationVerified(final RequestContext requestContext, final OneTimeTokenAccount account) {View on GitHub (pinned to e7288fc434)