apereo/cas · error · AuthenticationException

Unable to extract credentials for multifactor authentication

Error message

Unable to extract credentials for multifactor authentication

What it means

During REST authentication, CAS resolved a multifactor trigger (a provider was selected by the MultifactorAuthenticationTriggerSelectionStrategy) but the credential factory could not extract the second-factor credentials from the request via fromAuthentication(...). Without MFA credentials the finalizeAuthenticationTransaction cannot proceed, so AuthenticationException is thrown.

Solutions

  1. Include the MFA provider's expected credential in the request body (e.g. otp / token / webauthn assertion parameter) alongside username/password.
  2. Confirm the MFA provider's REST credential extractor module is a dependency and registered with the REST credential factory.
  3. Check the multifactorTriggerSelectionStrategy configuration — if MFA should not be forced for this request, adjust the trigger strategy or service MFA policy.
  4. Verify the parameter names against the provider's documentation; provider versions rename fields.
  5. Test with debug logging on MultifactorAuthenticationTriggerSelectionStrategy and the credential factory to see which provider was selected and what it looked for.

Example fix

// before: MFA triggered but no OTP supplied
curl -X POST https://cas/cas/v1/tickets -d 'username=u&password=p'
// after: supply the second factor expected by the provider
curl -X POST https://cas/cas/v1/tickets -d 'username=u&password=p&otp=123456'
Defensive patterns

Strategy: validation

Validate before calling

// ensure the MFA credential field the selected provider expects is present
if (body == null || !body.containsKey("otp")) { // adjust to provider field
    // add second-factor credential before calling authenticate
}

Try / catch

try {
    Optional<AuthenticationResult> r = restAuthenticationService.authenticate(body, req, res);
} catch (AuthenticationException e) {
    // prompt user for second factor and retry with MFA credential
}

Prevention

When it happens

Trigger: The request hits a service/flow that triggers an MFA provider (per service policy, principal attribute, request parameter like authnMethod/mfaProvider, etc.), yet the request body contains no credentials the provider's extractor recognizes — e.g. missing OTP/one-time-token field, wrong parameter name, or extractor module for that provider not registered in the REST credential factory.

Common situations: Client integrates the REST API and does not send the second-factor value (OTP) alongside the first-factor credentials; MFA provider forced globally by config but REST payloads never include OTP; provider changed (e.g. moving from webauthn to mfa-simple) so the expected request field changed; missing cas-server-support rest module for the specific MFA provider.

Understand the failure class

Related errors


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

Appendix: source

Thrown at core/cas-server-core-rest-api/src/main/java/org/apereo/cas/rest/authentication/DefaultRestAuthenticationService.java:76

        }
        val service = serviceFactory.createService(request);
        val registeredService = servicesManager.findServiceBy(service);
        val authResult = Optional.ofNullable(
            authenticationSystemSupport.handleInitialAuthenticationTransaction(service, credentials.toArray(Credential[]::new)));

        return authResult
            .map(result -> result.getInitialAuthentication()
                .filter(Unchecked.predicate(authn -> restAuthenticationPolicy.isSatisfiedBy(authn, applicationContext).isSuccess()))
                .filter(Unchecked.predicate(authn -> {
                    val validationResult = requestedContextValidator.validateAuthenticationContext(request, response, registeredService, authn, service);
                    return !validationResult.isSuccess();
                }))
                .map(Unchecked.function(authn -> multifactorTriggerSelectionStrategy.resolve(request, response, registeredService, authn, service)
                    .map(Unchecked.function(provider -> {
                        LOGGER.debug("Extracting credentials for multifactor authentication via [{}]", provider);
                        val authnCredentials = credentialFactory.fromAuthentication(request, requestBody, authn, provider);
                        if (authnCredentials == null || authnCredentials.isEmpty()) {
                            throw new AuthenticationException("Unable to extract credentials for multifactor authentication");
                        }
                        return authenticationSystemSupport.finalizeAuthenticationTransaction(service, authnCredentials);
                    }))
                    .orElseGet(Unchecked.supplier(() -> authenticationSystemSupport.finalizeAllAuthenticationTransactions(result, service)))))
                .orElseGet(Unchecked.supplier(() -> authenticationSystemSupport.finalizeAllAuthenticationTransactions(result, service))));
    }
}

View on GitHub (pinned to e7288fc434)