{"record":{"id":"7d579facbcb55791","repo":"apereo/cas","slug":"no-credentials-can-be-extracted-to-authenticate-th","errorCode":null,"errorMessage":"No credentials can be extracted to authenticate the REST request","messagePattern":"No credentials can be extracted to authenticate the REST request","errorType":"exception","errorClass":"BadRestRequestException","httpStatus":400,"severity":"error","filePath":"core/cas-server-core-rest-api/src/main/java/org/apereo/cas/rest/authentication/DefaultRestAuthenticationService.java","lineNumber":57,"sourceCode":"\n    private final ServiceFactory<WebApplicationService> serviceFactory;\n\n    private final MultifactorAuthenticationTriggerSelectionStrategy multifactorTriggerSelectionStrategy;\n\n    private final ServicesManager servicesManager;\n\n    private final RequestedAuthenticationContextValidator requestedContextValidator;\n\n    private final AuthenticationPolicy restAuthenticationPolicy;\n\n    private final ConfigurableApplicationContext applicationContext;\n\n    @Override\n    public Optional<AuthenticationResult> authenticate(final MultiValueMap<String, String> requestBody,\n                                                       final HttpServletRequest request, final HttpServletResponse response) throws Throwable {\n        val credentials = credentialFactory.fromRequest(request, requestBody);\n        if (credentials == null || credentials.isEmpty()) {\n            throw new BadRestRequestException(\"No credentials can be extracted to authenticate the REST request\");\n        }\n        val service = serviceFactory.createService(request);\n        val registeredService = servicesManager.findServiceBy(service);\n        val authResult = Optional.ofNullable(\n            authenticationSystemSupport.handleInitialAuthenticationTransaction(service, credentials.toArray(Credential[]::new)));\n\n        return authResult\n            .map(result -> result.getInitialAuthentication()\n                .filter(Unchecked.predicate(authn -> restAuthenticationPolicy.isSatisfiedBy(authn, applicationContext).isSuccess()))\n                .filter(Unchecked.predicate(authn -> {\n                    val validationResult = requestedContextValidator.validateAuthenticationContext(request, response, registeredService, authn, service);\n                    return !validationResult.isSuccess();\n                }))\n                .map(Unchecked.function(authn -> multifactorTriggerSelectionStrategy.resolve(request, response, registeredService, authn, service)\n                    .map(Unchecked.function(provider -> {\n                        LOGGER.debug(\"Extracting credentials for multifactor authentication via [{}]\", provider);\n                        val authnCredentials = credentialFactory.fromAuthentication(request, requestBody, authn, provider);\n                        if (authnCredentials == null || authnCredentials.isEmpty()) {","sourceCodeStart":39,"sourceCodeEnd":75,"githubUrl":"https://github.com/apereo/cas/blob/e7288fc434b4f4505b8452e1a57e8fb3111bb863/core/cas-server-core-rest-api/src/main/java/org/apereo/cas/rest/authentication/DefaultRestAuthenticationService.java#L39-L75","documentation":"The REST authentication endpoint could not produce any Credential from the incoming request. Credential extractors configured in the REST credential factory found nothing in the request body or headers, so no authentication transaction can start and BadRestRequestException is thrown (typically surfacing as HTTP 400).","triggerScenarios":"POSTing to /v1/tickets (or the REST authentication API) with a body that no registered RestCredentialFactory understands — e.g. missing 'username'/'password' form fields, wrong Content-Type (JSON instead of application/x-www-form-urlencoded when only form extraction is configured), empty body, or missing bearer/basic header for header-based extraction.","commonSituations":"Clients sending JSON to an endpoint that only parses form parameters; forgetting to add a credential extractor module (e.g. custom token extractor) so the factory returns an empty list; typos in parameter names (user vs username); proxies consuming the body before CAS sees it.","solutions":["Send credentials as application/x-www-form-urlencoded with 'username' and 'password' fields to POST /cas/v1/tickets.","Verify the Content-Type header matches what the configured credential extractor expects.","If using header-based auth (basic/bearer/token), confirm the corresponding CAS REST support module and extractor are on the classpath and enabled.","Check the factory configuration for custom RestCredentialFactory beans and confirm the parameter names it expects match the client's payload.","Inspect cas-server logs at debug level to see which extractors ran and rejected the body."],"exampleFix":"// before: JSON body not understood by form extractor\ncurl -X POST https://cas/cas/v1/tickets -H 'Content-Type: application/json' -d '{\"username\":\"u\",\"password\":\"p\"}'\n// after: form-encoded credentials\ncurl -X POST https://cas/cas/v1/tickets -H 'Content-Type: application/x-www-form-urlencoded' -d 'username=u&password=p'","handlingStrategy":"validation","validationCode":"if (body == null || body.isEmpty() ||\n    !body.containsKey(\"username\") || !body.containsKey(\"password\")) {\n    // fix payload before calling authenticate\n}","typeGuard":null,"tryCatchPattern":"try {\n    Optional<AuthenticationResult> r = restAuthenticationService.authenticate(body, req, res);\n} catch (BadRestRequestException e) {\n    // return HTTP 400 with e.getMessage()\n}","preventionTips":["Always POST form-encoded username/password (or the extractor's expected fields) to /v1/tickets.","Set Content-Type explicitly in REST clients.","Confirm the credential-extractor modules you rely on are on the classpath.","Log the outbound payload once during integration to verify field names."],"tags":["rest","authentication","credentials","http"],"backgroundTag":"missing-credentials","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"}