apereo/cas · error

Unable to determine google authenticator token credential

Error message

Unable to determine google authenticator token credential

What it means

The same action next fetches the GoogleAuthenticatorTokenCredential from the request context. If no credential was submitted (token form not filled or bound) the action logs this warning, adds an error message, and returns error(). A related guard also rejects credentials whose accountId does not match the selected account.

Solutions

  1. Ensure the token input field is submitted (non-empty) so the credential is created and bound in the prior flow state
  2. Re-select the correct device so the credential's accountId matches the account loaded into scope
  3. Check the MFA webflow form binding/bean configuration so GoogleAuthenticatorTokenCredential is instantiated from the request
  4. Perform the login through the normal webflow (not direct requests) so scope and credential are populated

Example fix

// before: skipping the token field
// POST ...token= (empty)
// after: always submit a fresh 6-digit code bound to the selected device
// POST ... token=123456&accountId=42
Defensive patterns

Strategy: validation

Validate before calling

GoogleAuthenticatorTokenCredential cred =
    WebUtils.getCredential(requestContext, GoogleAuthenticatorTokenCredential.class);
boolean ready = cred != null
    && cred.getToken() != null && cred.getToken().matches("\\d{6}")
    && cred.getAccountId() != null;

Try / catch

Event e = action.execute(requestContext);
if ("error".equals(e.getId())) {
    // re-render the token form so a credential is bound on resubmit
}

Prevention

When it happens

Trigger: doExecuteInternal runs with WebUtils.getCredential(requestContext, GoogleAuthenticatorTokenCredential.class) returning null — the credential was never created because the token field was empty or the prior state did not bind it; also when credential.getAccountId() is null or != account.getId().

Common situations: User submits the MFA form without entering a code; form binding misconfigured so GoogleAuthenticatorTokenCredential is not instantiated; user switched selected device but the submitted credential still references the old accountId; direct POST to the endpoint bypassing the flow.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


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

Appendix: source

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

    }

    @Override
    protected @Nullable Event doExecuteInternal(final RequestContext requestContext) {
        if (MultifactorAuthenticationTrustUtils.isMultifactorAuthenticationTrustedInScope(requestContext)) {
            val trustedDevice = MultifactorAuthenticationTrustUtils.getMultifactorAuthenticationTrustRecord(requestContext, MultifactorAuthenticationTrustRecord.class).orElseThrow();
            LOGGER.info("Multifactor authentication device [{}] is trusted with fingerprint [{}]", trustedDevice.getName(), trustedDevice.getDeviceFingerprint());
            return success(trustedDevice);
        }

        val account = MultifactorAuthenticationWebflowUtils.getOneTimeTokenAccount(requestContext, OneTimeTokenAccount.class);
        if (account == null) {
            LOGGER.warn("Unable to determine google authenticator account");
            addErrorMessageToContext(requestContext);
            return error();
        }
        val credential = WebUtils.getCredential(requestContext, GoogleAuthenticatorTokenCredential.class);
        if (credential == null) {
            LOGGER.warn("Unable to determine google authenticator token credential");
            addErrorMessageToContext(requestContext);
            return error();
        }
        LOGGER.trace("Located account [{}] to be used for credential [{}]", account, credential);
        if (credential.getAccountId() == null || credential.getAccountId() != account.getId()) {
            LOGGER.warn("Google authenticator token credential is not assigned a valid account id");
            addErrorMessageToContext(requestContext);
            return error();
        }
        return null;
    }
}

View on GitHub (pinned to e7288fc434)