apereo/cas · error · BadRestRequestException

No credentials can be extracted to authenticate the REST…

Error message

No credentials can be extracted to authenticate the REST request

What it means

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).

Solutions

  1. Send credentials as application/x-www-form-urlencoded with 'username' and 'password' fields to POST /cas/v1/tickets.
  2. Verify the Content-Type header matches what the configured credential extractor expects.
  3. If using header-based auth (basic/bearer/token), confirm the corresponding CAS REST support module and extractor are on the classpath and enabled.
  4. Check the factory configuration for custom RestCredentialFactory beans and confirm the parameter names it expects match the client's payload.
  5. Inspect cas-server logs at debug level to see which extractors ran and rejected the body.

Example fix

// before: JSON body not understood by form extractor
curl -X POST https://cas/cas/v1/tickets -H 'Content-Type: application/json' -d '{"username":"u","password":"p"}'
// after: form-encoded credentials
curl -X POST https://cas/cas/v1/tickets -H 'Content-Type: application/x-www-form-urlencoded' -d 'username=u&password=p'
Defensive patterns

Strategy: validation

Validate before calling

if (body == null || body.isEmpty() ||
    !body.containsKey("username") || !body.containsKey("password")) {
    // fix payload before calling authenticate
}

Try / catch

try {
    Optional<AuthenticationResult> r = restAuthenticationService.authenticate(body, req, res);
} catch (BadRestRequestException e) {
    // return HTTP 400 with e.getMessage()
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Understand the failure class

Related errors


AI-assisted analysis of apereo/cas@e7288fc434 (2026-09-08). Data as JSON: /api/errors/7d579facbcb55791. Report an issue: GitHub.

Appendix: source

Thrown at core/cas-server-core-rest-api/src/main/java/org/apereo/cas/rest/authentication/DefaultRestAuthenticationService.java:57

    private final ServiceFactory<WebApplicationService> serviceFactory;

    private final MultifactorAuthenticationTriggerSelectionStrategy multifactorTriggerSelectionStrategy;

    private final ServicesManager servicesManager;

    private final RequestedAuthenticationContextValidator requestedContextValidator;

    private final AuthenticationPolicy restAuthenticationPolicy;

    private final ConfigurableApplicationContext applicationContext;

    @Override
    public Optional<AuthenticationResult> authenticate(final MultiValueMap<String, String> requestBody,
                                                       final HttpServletRequest request, final HttpServletResponse response) throws Throwable {
        val credentials = credentialFactory.fromRequest(request, requestBody);
        if (credentials == null || credentials.isEmpty()) {
            throw new BadRestRequestException("No credentials can be extracted to authenticate the REST request");
        }
        val service = serviceFactory.createService(request);
        val registeredService = servicesManager.findServiceBy(service);
        val authResult = Optional.ofNullable(
            authenticationSystemSupport.handleInitialAuthenticationTransaction(service, credentials.toArray(Credential[]::new)));

        return authResult
            .map(result -> result.getInitialAuthentication()
                .filter(Unchecked.predicate(authn -> restAuthenticationPolicy.isSatisfiedBy(authn, applicationContext).isSuccess()))
                .filter(Unchecked.predicate(authn -> {
                    val validationResult = requestedContextValidator.validateAuthenticationContext(request, response, registeredService, authn, service);
                    return !validationResult.isSuccess();
                }))
                .map(Unchecked.function(authn -> multifactorTriggerSelectionStrategy.resolve(request, response, registeredService, authn, service)
                    .map(Unchecked.function(provider -> {
                        LOGGER.debug("Extracting credentials for multifactor authentication via [{}]", provider);
                        val authnCredentials = credentialFactory.fromAuthentication(request, requestBody, authn, provider);
                        if (authnCredentials == null || authnCredentials.isEmpty()) {

View on GitHub (pinned to e7288fc434)