apereo/cas · error

No client id is provided in the request

Error message

No client id is provided in the request

What it means

OAuth20PasswordGrantTypeTokenRequestValidator.validateInternal() requires a clientId resolved either from the request parameters (Basic auth header or form body) or from the authenticated user profile. If both are blank the validator logs this warning and returns false, rejecting the password-grant token request before looking up the registered service.

Solutions

  1. Include client_id as a request parameter or an HTTP Basic Authorization header in the token request.
  2. Check that any reverse proxy does not strip the Authorization header before CAS receives it.
  3. Verify the client library sends the parameter name exactly as `client_id` with a non-blank value.
  4. If the client is supposed to be public, ensure the profile carries the CLIENT_ID attribute (client authenticated upstream).

Example fix

// before
curl -d 'grant_type=password&username=u&password=p' https://cas/oauth2.0/token
// after
curl -u myClient:secret -d 'grant_type=password&username=u&password=p' https://cas/oauth2.0/token
Defensive patterns

Strategy: validation

Validate before calling

const clientId = params.client_id || basicAuthUser || profile?.client_id;
if (!clientId || !clientId.trim()) {
  throw new Error('client_id required for password grant token request');
}

Prevention

When it happens

Trigger: A POST to the token endpoint with grant_type=password that omits client_id, omits the HTTP Basic Authorization header, and has no clientId attribute in the Pac4j user profile.

Common situations: Client sends only username/password without client credentials; Basic auth header malformed or stripped by a reverse proxy; client_id supplied under a misspelled parameter name; public-client setups that expect clientId to be optional.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


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

Appendix: source

Thrown at support/cas-server-support-oauth-core-api/src/main/java/org/apereo/cas/support/oauth/validator/token/OAuth20PasswordGrantTypeTokenRequestValidator.java:45

    public OAuth20PasswordGrantTypeTokenRequestValidator(final ObjectProvider<OAuth20ConfigurationContext> configurationContext) {
        super(configurationContext);
    }

    @Override
    protected OAuth20GrantTypes getGrantType() {
        return OAuth20GrantTypes.PASSWORD;
    }

    @Override
    protected boolean validateInternal(final WebContext context, final String grantType,
                                       final ProfileManager manager, final UserProfile uProfile) throws Throwable {

        val configurationContext = getConfigurationContext().getObject();
        val callContext = new CallContext(context, configurationContext.getSessionStore());
        val clientIdAndSecret = configurationContext.getRequestParameterResolver().resolveClientIdAndClientSecret(callContext);
        val clientId = StringUtils.defaultIfBlank(clientIdAndSecret.getKey(), (String) uProfile.getAttribute(OAuth20Constants.CLIENT_ID));
        if (StringUtils.isBlank(clientId)) {
            LOGGER.warn("No client id is provided in the request");
            return false;
        }
        LOGGER.debug("Received grant type [{}] with client id [{}]", grantType, clientId);
        val registeredService = OAuth20Utils.getRegisteredOAuthServiceByClientId(configurationContext.getServicesManager(), clientId);
        RegisteredServiceAccessStrategyUtils.ensureServiceAccessIsAllowed(registeredService);
        val service = configurationContext.getWebApplicationServiceServiceFactory().createService(registeredService.getServiceId());
        val audit = AuditableContext.builder()
            .service(service)
            .registeredService(registeredService)
            .build();
        val accessResult = configurationContext.getRegisteredServiceAccessStrategyEnforcer().execute(audit);
        accessResult.throwExceptionIfNeeded();

        if (!isGrantTypeSupportedBy(registeredService, grantType)) {
            LOGGER.warn("Requested grant type [{}] is not authorized by service definition [{}]",
                grantType, registeredService.getServiceId());
            return false;
        }

View on GitHub (pinned to e7288fc434)