{"record":{"id":"edd587f3fd42ca3c","repo":"apereo/cas","slug":"unable-to-validate-multifactor-credential-with-sta","errorCode":null,"errorMessage":"Unable to validate multifactor credential with status ","messagePattern":"Unable to validate multifactor credential with status ","errorType":"exception","errorClass":"FailedLoginException","httpStatus":null,"severity":"error","filePath":"support/cas-server-support-simple-mfa-core/src/main/java/org/apereo/cas/mfa/simple/validation/RestfulCasSimpleMultifactorAuthenticationService.java","lineNumber":90,"sourceCode":"                .entity(writer.toString())\n                .basicAuthPassword(properties.getBasicAuthPassword())\n                .basicAuthUsername(properties.getBasicAuthUsername())\n                .maximumRetryAttempts(properties.getMaximumRetryAttempts())\n                .parameters(parameters)\n                .build();\n            response = HttpUtils.execute(exec);\n            val statusCode = response.getCode();\n            if (HttpStatus.valueOf(statusCode).is2xxSuccessful()) {\n                try (val content = ((HttpEntityContainer) response).getEntity().getContent()) {\n                    val result = IOUtils.toString(content, StandardCharsets.UTF_8);\n                    val mfaFactory = (CasSimpleMultifactorAuthenticationTicketFactory) ticketFactory.get(CasSimpleMultifactorAuthenticationTicket.class);\n                    LOGGER.debug(\"Multifactor authentication token received is [{}]\", result);\n                    val token = mfaFactory.create(result, service, CollectionUtils.wrap(CasSimpleMultifactorAuthenticationConstants.PROPERTY_PRINCIPAL, principal));\n                    LOGGER.debug(\"Created multifactor authentication token [{}] for service [{}]\", token.getId(), service);\n                    return token;\n                }\n            }\n            throw new FailedLoginException(\"Unable to validate multifactor credential with status \" + statusCode);\n        } finally {\n            HttpUtils.close(response);\n        }\n    }\n\n    @Override\n    public void store(final CasSimpleMultifactorAuthenticationTicket token) throws Exception {\n        HttpResponse response = null;\n        try (val writer = new StringWriter()) {\n            MAPPER.writer().with(new MinimalPrettyPrinter()).writeValue(writer, token);\n\n            val headers = CollectionUtils.<String, String>wrap(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);\n            headers.putAll(properties.getHeaders());\n            val exec = HttpExecutionRequest.builder()\n                .method(HttpMethod.POST)\n                .headers(headers)\n                .url(properties.getUrl())\n                .entity(writer.toString())","sourceCodeStart":72,"sourceCodeEnd":108,"githubUrl":"https://github.com/apereo/cas/blob/e7288fc434b4f4505b8452e1a57e8fb3111bb863/support/cas-server-support-simple-mfa-core/src/main/java/org/apereo/cas/mfa/simple/validation/RestfulCasSimpleMultifactorAuthenticationService.java#L72-L108","documentation":"RestfulCasSimpleMultifactorAuthenticationService.generate calls an external REST endpoint to validate the user's MFA credential and mint a simple-MFA token. If the endpoint responds with an unexpected/non-success statusCode (not the accepted success status with a token payload), it throws FailedLoginException \"Unable to validate multifactor credential with status <statusCode>\". The MFA decision was delegated to the REST service and it refused or errored.","triggerScenarios":"generate() when the HTTP response from the configured simple-mfa REST endpoint returns a status code outside the expected success range, or a success status without the expected token body — e.g. 401/403 wrong code, 404/500 endpoint problems.","commonSituations":"Remote MFA service rejecting the submitted code (wrong/expired code); wrong REST endpoint URL or credentials configured for the MFA REST service; the remote service returning an undocumented status or empty body on success; network/proxy layer returning 502/503.","solutions":["Check the remote MFA REST service's response status and logs for why validation failed","Verify cas.authn.mfa.rest (simple-mfa REST) endpoint URL, method, and auth credentials are correct","Confirm the remote service returns the expected body/token format on success","Retry after fixing the upstream service; treat 5xx as transient and re-attempt the MFA step"],"exampleFix":null,"handlingStrategy":"retry","validationCode":"// preflight the REST MFA endpoint availability and expected contract\nvar probe = HttpUtils.executeHttpRequestToServices(...mfaRestUrl, HttpMethod.GET, ...);\nif (probe.getStatus() != 200) throw new IllegalStateException(\"MFA REST endpoint unhealthy: \" + probe.getStatus());","typeGuard":null,"tryCatchPattern":"try {\n    return restMfaService.generate(principal, service, credential);\n} catch (FailedLoginException e) {\n    if (isServerError(statusCode)) { // 5xx: transient upstream issue\n        return retryWithBackoff(() -> restMfaService.generate(principal, service, credential));\n    }\n    throw e; // 4xx: user's code genuinely rejected; prompt for a new code\n}","preventionTips":["Health-check the MFA REST endpoint in deployment pipelines","Verify endpoint URL, HTTP method, and auth headers in cas.authn.mfa.rest configuration","Match the exact response status/body the remote service returns on success","Distinguish 4xx (bad code, prompt user) from 5xx (upstream issue, retry) in handling"],"tags":["mfa","rest","http-status","external-service"],"backgroundTag":"http-error-response","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"}