{"record":{"id":"41b85bd38239add7","repo":"apereo/cas","slug":"no-registered-devices-for-multifactor-authenticati-41b85b","errorCode":null,"errorMessage":"No registered devices for multifactor authentication could be found for [{}]","messagePattern":"No registered devices for multifactor authentication could be found for \\[(.+?)\\]","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"support/cas-server-support-pm-webflow/src/main/java/org/apereo/cas/pm/web/flow/actions/SendPasswordResetInstructionsAction.java","lineNumber":132,"sourceCode":"            return getErrorEvent(\"contact.failed\", \"Unable to send email as no mail sender is defined\", requestContext);\n        }\n\n        val query = buildPasswordManagementQuery(requestContext);\n        if (StringUtils.isBlank(query.getUsername())) {\n            return getErrorEvent(\"username.required\", \"No username is provided\", requestContext);\n        }\n\n        val emails = locatePasswordResetRequestEmail(requestContext, query);\n        val phones = locatePasswordResetRequestPhone(requestContext, query);\n\n        if (emails.isEmpty() && phones.isEmpty()) {\n            LOGGER.warn(\"No recipient is provided with a valid email/phone\");\n            return getInvalidContactEvent(requestContext);\n        }\n        WebUtils.putPasswordManagementQuery(requestContext, query);\n        if (doesPasswordResetRequireMultifactorAuthentication(requestContext)\n            && !hasPrincipalRegisteredMultifactorAuthenticationDevice(requestContext)) {\n            LOGGER.warn(\"No registered devices for multifactor authentication could be found for [{}]\", query.getUsername());\n            WebUtils.addErrorMessageToContext(requestContext, \"screen.mfaDenied.message\");\n            return eventFactory.event(this, CasWebflowConstants.TRANSITION_ID_DENY);\n        }\n        val service = WebUtils.getService(requestContext);\n        val url = buildPasswordResetUrl(query.getUsername(), service);\n        if (url != null) {\n            val sendEmail = sendPasswordResetEmailToAccount(query.getUsername(), emails, url, requestContext);\n            val sendSms = sendPasswordResetSmsToAccount(requestContext, phones, url);\n            if (sendEmail.isSuccess() || sendSms) {\n                return success(url);\n            }\n        } else {\n            LOGGER.error(\"No password reset URL could be built and sent to [{}]\", emails);\n        }\n        LOGGER.error(\"Failed to notify account [{}]\", emails);\n        return getErrorEvent(\"contact.failed\", \"Failed to send the password reset link via email address or phone\", requestContext);\n    }\n","sourceCodeStart":114,"sourceCodeEnd":150,"githubUrl":"https://github.com/apereo/cas/blob/e7288fc434b4f4505b8452e1a57e8fb3111bb863/support/cas-server-support-pm-webflow/src/main/java/org/apereo/cas/pm/web/flow/actions/SendPasswordResetInstructionsAction.java#L114-L150","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\ncas.authn.pm.reset.mfa-enabled=true\n// user has no registered devices -> deny\n// after — either enroll the user, or:\ncas.authn.pm.reset.mfa-enabled=false","handlingStrategy":"fallback","validationCode":"boolean mfaRequired = casProperties.getAuthn().getPm().getReset().isMfaEnabled();\nboolean hasDevices = mfaDeviceRegistry.findDevices(principalId).size() > 0;\nif (mfaRequired && !hasDevices) {\n    // guide user to MFA enrollment before requesting a password reset\n}","typeGuard":"boolean hasRegisteredDevices(String principalId, MfaDeviceRegistry r) {\n    return !r.findDevices(principalId).isEmpty();\n}","tryCatchPattern":null,"preventionTips":["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"],"tags":["mfa","password-reset","webflow","security"],"backgroundTag":"feature-not-enabled","analyzedSha":"e7288fc434b4f4505b8452e1a57e8fb3111bb863","analyzedAt":"2026-09-08T15:39:16.015Z","contentChangedAt":"2026-09-08T15:39:16.015Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}