apereo/cas · warning
Token [ ] has exceeded the maximum number of attempts [ ]
Error message
Token [{}] has exceeded the maximum number of attempts [{}] What it means
GoogleAuthenticatorAuthorizeTokenAttemptAction limits how many times a token can be submitted for verification within a webflow session. When the stored attemptCounter reaches maxAllowedAttempts (maxCheckAttempts minus allowed margin logic in the source), it warns 'Token [{}] has exceeded the maximum number of attempts [{}]' and returns an error event, blocking further attempts for that credential.
Solutions
- Increase cas.authn.mfa.gauth.max-check-attempts (or core token attempt settings) if legitimate users hit the cap
- Start a new authentication flow (restart the webflow) which resets the flow-scope attempt counter
- Investigate the repeated attempts in the log for brute-force patterns and consider rate limiting
- Verify the user's authenticator app clock drift if failures are legitimate
Example fix
// before cas.authn.mfa.gauth.max-check-attempts=1 // after cas.authn.mfa.gauth.max-check-attempts=5
Defensive patterns
Strategy: validation
Validate before calling
if (attemptCounter >= maxCheckAttempts) {
return error(); // caller-side check before submitting another token
} Try / catch
try { ... } catch (Exception e) { /* this is a webflow event, not exception; handle the 'error' transition by restarting the flow */ } Prevention
- Set max-check-attempts to a sane value (3-5)
- Educate users the flow locks after N bad codes
- Rate-limit OTP submissions server-side
- Check authenticator clock drift to reduce legitimate failures
When it happens
Trigger: A user (or an automated script) submits an incorrect Google Authenticator OTP credential to the webflow more times than the configured maximum during one authentication flow session.
Common situations: Brute-force attempts on OTP codes, users repeatedly mistyping codes, or very low maxCheckAttempts configuration making legitimate users hit the cap; token id in the log identifies the credential.
Related errors
- Failed to authenticate code
- cannot be found in the registry
- cannot reuse OTP
- Failed to authenticate code
- Failed to authenticate code
AI-assisted analysis of apereo/cas@e7288fc434 (2026-09-08).
Data as JSON: /api/errors/211980add8d842eb.
Report an issue: GitHub.
Appendix: source
Thrown at support/cas-server-support-gauth-core/src/main/java/org/apereo/cas/gauth/web/flow/GoogleAuthenticatorAuthorizeTokenAttemptAction.java:39
@Slf4j
public class GoogleAuthenticatorAuthorizeTokenAttemptAction extends BaseCasWebflowAction {
private static final String FLOW_SCOPE_ATTEMPT_COUNTER = "GoogleAuthenticatorTokenAttemptCount";
private final CasConfigurationProperties casProperties;
@Override
protected @Nullable Event doExecuteInternal(final RequestContext requestContext) {
val maxAllowedAttempts = casProperties.getAuthn().getMfa().getGauth().getCore().getMaximumAuthenticationAttempts();
val credential = Objects.requireNonNull(WebUtils.getCredential(requestContext));
var attemptCounter = requestContext.getFlowScope().get(FLOW_SCOPE_ATTEMPT_COUNTER, Integer.class, 0);
LOGGER.debug("Attempt counter for token [{}] is [{}]", credential.getId(), attemptCounter);
if (maxAllowedAttempts <= 0 || attemptCounter < maxAllowedAttempts) {
LOGGER.debug("Token [{}] is allowed to proceed with authentication", credential.getId());
attemptCounter++;
requestContext.getFlowScope().put(FLOW_SCOPE_ATTEMPT_COUNTER, attemptCounter);
return success(attemptCounter);
}
LOGGER.warn("Token [{}] has exceeded the maximum number of attempts [{}]", credential.getId(), attemptCounter);
return error();
}
}
View on GitHub (pinned to e7288fc434)