apereo/cas · warning

Unable to authorize given token

Error message

Unable to authorize given token [{}] for account [{}]

What it means

GoogleAuthenticatorSaveRegistrationAction.validate() checks the submitted token via validator.isTokenAuthorizedFor(token, account). If not authorized it logs this warning and returns false, so the registration save (new secret/token store entry) is refused.

Solutions

  1. Have the user enter a new code generated immediately after scanning the QR code for this specific account
  2. Verify the account object passed to validate() matches the QR code that was scanned (same username/secret)
  3. Synchronize clocks and, if needed, widen the token validation window in cas.authn.mfa.gauth.* settings
  4. Retry the registration flow to regenerate a fresh secret and QR code
Defensive patterns

Strategy: retry

Validate before calling

boolean codeLooksValid = code != null && code.matches("\\d{6}");
// confirm account/secret freshly provisioned before validate()

Try / catch

boolean ok = action.validate(token, account);
if (!ok) {
    // retry registration with a newly generated secret/QR
}

Prevention

When it happens

Trigger: validate() invoked with a token that does not validate against the given account's secret — wrong code typed during registration, expired window, or token not for this account; the fallback function also yields false on exceptions.

Common situations: User enters a code from a different account's entry in their authenticator app; delay between QR scan and code entry exceeds the window; server clock drift; duplicated registration attempts consuming tokens.

Related errors


AI-assisted analysis of apereo/cas@e7288fc434 (2026-09-08). Data as JSON: /api/errors/c957e991e0a7f7c6. Report an issue: GitHub.

Appendix: source

Thrown at support/cas-server-support-gauth-core/src/main/java/org/apereo/cas/gauth/web/flow/GoogleAuthenticatorSaveRegistrationAction.java:54

        final OneTimeTokenCredentialRepository repository,
        final CasConfigurationProperties casProperties,
        final OneTimeTokenCredentialValidator<GoogleAuthenticatorTokenCredential, GoogleAuthenticatorToken> validator,
        final TenantExtractor tenantExtractor) {
        super(repository, casProperties, tenantExtractor);
        this.validator = validator;
    }

    @Override
    protected boolean validate(final GoogleAuthenticatorAccount account, final RequestContext requestContext) {
        return FunctionUtils.doAndHandle(_ -> {
            val token = requestContext.getRequestParameters().getRequiredInteger(REQUEST_PARAMETER_TOKEN);
            if (validator.isTokenAuthorizedFor(token, account)) {
                LOGGER.debug("Successfully validated token [{}]", token);
                val googleAuthenticatorToken = new GoogleAuthenticatorToken(token, account.getUsername());
                validator.getTokenRepository().store(googleAuthenticatorToken);
                return true;
            }
            LOGGER.warn("Unable to authorize given token [{}] for account [{}]", token, account);
            return false;
        }, e -> false)
        .apply(account);
    }

    @Override
    protected Event getErrorEvent(final RequestContext requestContext) {
        val response = WebUtils.getHttpServletResponseFromExternalWebflowContext(requestContext);
        response.setStatus(HttpStatus.UNAUTHORIZED.value());
        return error();
    }

    @Override
    protected GoogleAuthenticatorAccount buildOneTimeTokenAccount(final RequestContext requestContext) {
        val acct = super.buildOneTimeTokenAccount(requestContext);
        return GoogleAuthenticatorAccount.from(acct);
    }
}

View on GitHub (pinned to e7288fc434)