apereo/cas · warning
No registered devices for multifactor authentication could…
Error message
No registered devices for multifactor authentication could be found for [{}] What it means
After contact info is validated, SendPasswordResetInstructionsAction checks whether password reset requires MFA and, if so, whether the principal has any registered MFA devices. With no registered devices it logs this warn, adds the screen.mfaDenied message, and returns the 'deny' transition so no reset link is issued.
Solutions
- Have the user enroll an MFA device via the normal MFA registration flow first
- Relax cas.authn.pm.reset mfa requirements (e.g. remove required provider) if MFA should not gate resets
- Verify the MFA device registry/storage (e.g. mongo, json, redis) is configured and contains the user's records
- Confirm the principal resolution produces the same principal id used when devices were registered
Example fix
// before cas.authn.pm.reset.mfa-enabled=true // user has no registered devices -> deny // after — either enroll the user, or: cas.authn.pm.reset.mfa-enabled=false
Defensive patterns
Strategy: fallback
Validate before calling
boolean mfaRequired = casProperties.getAuthn().getPm().getReset().isMfaEnabled();
boolean hasDevices = mfaDeviceRegistry.findDevices(principalId).size() > 0;
if (mfaRequired && !hasDevices) {
// guide user to MFA enrollment before requesting a password reset
} Type guard
boolean hasRegisteredDevices(String principalId, MfaDeviceRegistry r) {
return !r.findDevices(principalId).isEmpty();
} Prevention
- Roll out MFA-for-PM policies together with an enrollment campaign
- Monitor deny transitions in the PM flow as a signal of unenrolled users
- Ensure the MFA device registry store is shared with the PM webflow deployment
When it happens
Trigger: doesPasswordResetRequireMultifactorAuthentication(requestContext) is true (per cas.authn.pm.reset.mfa or registered-service policy) while hasPrincipalRegisteredMultifactorAuthenticationDevice finds zero device registrations for the user's principal.
Common situations: MFA required for PM reset but user never enrolled (no WebAuthn/Google Authenticator/TOTP records); principal attribute used to locate devices is missing; MFA provider's account registry store is empty or misconnected; policy recently changed to require MFA for existing users.
Understand the failure class
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
- State [ : : ] does not have a matching transition for
- Unknown Duo Security authentication attempt
- Failed to authenticate code
- Unauthorized account registration attempt for id
- Failed to authenticate code
AI-assisted analysis of apereo/cas@e7288fc434 (2026-09-08).
Data as JSON: /api/errors/41b85bd38239add7.
Report an issue: GitHub.
Appendix: source
Thrown at support/cas-server-support-pm-webflow/src/main/java/org/apereo/cas/pm/web/flow/actions/SendPasswordResetInstructionsAction.java:132
return getErrorEvent("contact.failed", "Unable to send email as no mail sender is defined", requestContext);
}
val query = buildPasswordManagementQuery(requestContext);
if (StringUtils.isBlank(query.getUsername())) {
return getErrorEvent("username.required", "No username is provided", requestContext);
}
val emails = locatePasswordResetRequestEmail(requestContext, query);
val phones = locatePasswordResetRequestPhone(requestContext, query);
if (emails.isEmpty() && phones.isEmpty()) {
LOGGER.warn("No recipient is provided with a valid email/phone");
return getInvalidContactEvent(requestContext);
}
WebUtils.putPasswordManagementQuery(requestContext, query);
if (doesPasswordResetRequireMultifactorAuthentication(requestContext)
&& !hasPrincipalRegisteredMultifactorAuthenticationDevice(requestContext)) {
LOGGER.warn("No registered devices for multifactor authentication could be found for [{}]", query.getUsername());
WebUtils.addErrorMessageToContext(requestContext, "screen.mfaDenied.message");
return eventFactory.event(this, CasWebflowConstants.TRANSITION_ID_DENY);
}
val service = WebUtils.getService(requestContext);
val url = buildPasswordResetUrl(query.getUsername(), service);
if (url != null) {
val sendEmail = sendPasswordResetEmailToAccount(query.getUsername(), emails, url, requestContext);
val sendSms = sendPasswordResetSmsToAccount(requestContext, phones, url);
if (sendEmail.isSuccess() || sendSms) {
return success(url);
}
} else {
LOGGER.error("No password reset URL could be built and sent to [{}]", emails);
}
LOGGER.error("Failed to notify account [{}]", emails);
return getErrorEvent("contact.failed", "Failed to send the password reset link via email address or phone", requestContext);
}
View on GitHub (pinned to e7288fc434)