apereo/cas · error · AuthenticationException
No multifactor authentication providers are specified to…
Error message
No multifactor authentication providers are specified to handle risk-based authentication
What it means
When no explicit risk-response MFA provider is configured, executeInternal() discovers all available MFA providers. If exactly one is found it is used automatically; if more than one is available and none was specified, CAS cannot choose, logs this warning, and throws AuthenticationException wrapping MultifactorAuthenticationProviderAbsentException, blocking authentication. The deployer must explicitly select a provider when several exist.
Solutions
- Set cas.authn.adaptive.risk.response.mfa-provider to the id of the intended provider (e.g. mfa-duo).
- Verify the configured id matches a registered provider's id from MultifactorAuthenticationUtils.getAvailableMultifactorAuthenticationProviders.
- Disable or remove the unwanted MFA module so only one provider remains registered.
- Alternatively rely on registered-service MFA policies and configure the risk response to a definite provider to avoid ambiguity.
Example fix
// before: multiple providers, none selected for risk response cas.authn.mfa.duo.enabled=true cas.authn.mfa.totp.enabled=true // after: explicitly select the provider for risky auth cas.authn.mfa.duo.enabled=true cas.authn.mfa.totp.enabled=true cas.authn.adaptive.risk.response.mfa-provider=mfa-duo
Defensive patterns
Strategy: validation
Validate before calling
val providers = MultifactorAuthenticationUtils
.getAvailableMultifactorAuthenticationProviders(applicationContext);
val configured = casProperties.getAuthn().getAdaptive().getRisk().getResponse().getMfaProvider();
if (providers.size() > 1 && StringUtils.isBlank(configured)) {
throw new IllegalStateException(
"Multiple MFA providers [" + providers.keySet() + "] available; set risk response mfa-provider");
} Try / catch
try {
contingencyPlan.handle(event, authentication, service, request);
} catch (AuthenticationException e) {
if (e.hasExceptionOfType(MultifactorAuthenticationProviderAbsentException.class)) {
LOGGER.error("Ambiguous risk-response MFA setup; no provider id configured");
throw new HttpRequestException("MFA provider unresolvable", HttpStatus.SERVICE_UNAVAILABLE);
}
throw e;
} Prevention
- Always set cas.authn.adaptive.risk.response.mfa-provider in multi-MFA deployments.
- After adding any new MFA module, re-verify the risk response provider id is still valid.
- Document provider ids (mfa-duo, mfa-totp, ...) in deployment configuration templates.
- Validate config at boot with a check that the configured provider id exists in the provider registry.
When it happens
Trigger: Risky authentication handled by MultifactorAuthenticationContingencyPlan while cas.authn.adaptive.risk.response.mfaProvider is blank and the context contains two or more registered MultifactorAuthenticationProvider beans (e.g. both Duo and TOTP configured).
Common situations: Overlay enables multiple MFA modules (common when mfa-duo and mfa-totp coexist) but the operator forgot to set the risk-response provider id; a newly added MFA module pushed the provider count from 1 to 2, breaking previously working implicit selection.
Understand the failure class
Background: "is required", "must be set", "missing required field": configuration validation errors across open-source libraries — this error's family across 36 libraries.
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
- No multifactor authentication providers are available in…
- No risk calculators are available to evaluate…
- State [ : : ] does not have a matching transition for
- Not all requested multifactor providers could be found…
- Unable to extract credentials for multifactor authentication
AI-assisted analysis of apereo/cas@e7288fc434 (2026-09-08).
Data as JSON: /api/errors/e1af0861c89494d9.
Report an issue: GitHub.
Appendix: source
Thrown at support/cas-server-support-electrofence/src/main/java/org/apereo/cas/impl/plans/MultifactorAuthenticationContingencyPlan.java:51
@Override
protected AuthenticationRiskContingencyResponse executeInternal(final Authentication authentication,
final RegisteredService service,
final AuthenticationRiskScore score,
final HttpServletRequest request) {
var id = casProperties.getAuthn().getAdaptive().getRisk().getResponse().getMfaProvider();
if (StringUtils.isBlank(id)) {
LOGGER.debug("No explicit multifactor authentication provider is defined to handle risk-based authentication.");
val providerMap = MultifactorAuthenticationUtils.getAvailableMultifactorAuthenticationProviders(this.applicationContext);
if (providerMap.isEmpty()) {
LOGGER.warn("No multifactor authentication providers are available in the application context. Authentication is blocked");
throw new AuthenticationException(new RiskyAuthenticationException());
}
if (providerMap.size() == 1) {
id = providerMap.values().iterator().next().getId();
} else {
LOGGER.warn("No multifactor authentication providers are specified to handle risk-based authentication");
throw new AuthenticationException(new MultifactorAuthenticationProviderAbsentException());
}
}
LOGGER.debug("Attempting to handle risk-based authentication via multifactor authentication provider [{}]", id);
val attributeName = casProperties.getAuthn().getAdaptive().getRisk().getResponse().getRiskyAuthenticationAttribute();
val newAuthn = DefaultAuthenticationBuilder.newInstance(authentication)
.addAttribute(attributeName, Boolean.TRUE)
.build();
LOGGER.debug("Updated authentication to remember risk-based authentication via [{}]", attributeName);
authentication.updateAttributes(newAuthn);
return new AuthenticationRiskContingencyResponse(new Event(this, id));
}
}
View on GitHub (pinned to e7288fc434)