apereo/cas · error

Response type [ ] or grant type [ ] is not supported.

Error message

Response type [{}] or grant type [{}] is not supported.

What it means

The device-code validator accepts a request only if it presents either response_type=device_code or grant_type=urn:ietf:params:oauth:grant-type:device_code. If neither parameter indicates the device-code flow, the validator logs this message and declines to handle the request, letting other token/authorization validators take over or fail. It signals the request was routed to the device endpoint with the wrong parameters.

Solutions

  1. Send response_type=device_code (device authorization start) or grant_type=urn:ietf:params:oauth:grant-type:device_code (token poll) as appropriate for the endpoint.
  2. Ensure the device client actually requests a device code from the device-authorization endpoint before polling the token endpoint.
  3. Enable the CAS device-code flow feature/config so the validator and its registered-service checks are active for your client.
  4. Check that grant_type is not being stripped or mangled by intermediate proxies or client HTTP form encoding.

Example fix

// before
POST /oauth2.0/token grant_type=authorization_code&code=ABC
// after (device token poll)
POST /oauth2.0/token grant_type=urn:ietf:params:oauth:grant-type:device_code&device_code=DEV123&client_id=app
Defensive patterns

Strategy: validation

Validate before calling

const DEVICE_GRANT = 'urn:ietf:params:oauth:grant-type:device_code';
if (!['device_code'].includes(responseType) && grantType !== DEVICE_GRANT) {
  throw new Error('request must be a device_code response/grant');
}

Type guard

const isDeviceCodeRequest = (p) => p.responseType === 'device_code' || p.grantType === 'urn:ietf:params:oauth:grant-type:device_code';

Prevention

When it happens

Trigger: POST /oauth2.0/token or the device endpoint with response_type=code / grant_type=authorization_code instead of device_code values; missing or empty grant_type parameter entirely.

Common situations: Developer points a standard authorization-code or password client at the device-token endpoint; client library omits grant_type on device access-token polls; migration from another IdP that used different device grant URIs.

Related errors


AI-assisted analysis of apereo/cas@e7288fc434 (2026-09-08). Data as JSON: /api/errors/b6a76a8e9c044cb2. 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/OAuth20DeviceCodeResponseTypeRequestValidator.java:52

    private final ServicesManager servicesManager;

    private final ServiceFactory<WebApplicationService> webApplicationServiceServiceFactory;

    private final OAuth20RequestParameterResolver requestParameterResolver;

    private int order = Ordered.LOWEST_PRECEDENCE;

    @Override
    public boolean validate(final WebContext context) {
        val responseType = requestParameterResolver.resolveRequestParameter(context, OAuth20Constants.RESPONSE_TYPE)
            .map(String::valueOf).orElse(StringUtils.EMPTY);
        val grantType = requestParameterResolver.resolveRequestParameter(context, OAuth20Constants.GRANT_TYPE)
            .map(String::valueOf).orElse(StringUtils.EMPTY);
        val validResponseType = OAuth20Utils.isResponseType(responseType, OAuth20ResponseTypes.DEVICE_CODE);
        val validGrantType = OAuth20Utils.isGrantType(grantType, OAuth20GrantTypes.DEVICE_CODE);

        if (!validResponseType && !validGrantType) {
            LOGGER.warn("Response type [{}] or grant type [{}] is not supported.", responseType, grantType);
            return false;
        }

        val clientId = requestParameterResolver.resolveRequestParameter(context, OAuth20Constants.CLIENT_ID).orElse(StringUtils.EMPTY);
        return FunctionUtils.doAndHandle(() -> {
            val registeredService = Objects.requireNonNull(OAuth20Utils.getRegisteredOAuthServiceByClientId(this.servicesManager, clientId));
            RegisteredServiceAccessStrategyUtils.ensureServiceAccessIsAllowed(registeredService);
            return (validResponseType && requestParameterResolver.isAuthorizedResponseTypeForService(context, registeredService))
                   || (validGrantType && requestParameterResolver.isAuthorizedGrantTypeForService(context, registeredService));
        }, t -> {
            LOGGER.warn("Registered service access is not allowed for service definition for client id [{}]", clientId);
            return false;
        }).get();
    }

    @Override
    public boolean supports(final WebContext context) {
        val responseType = requestParameterResolver.resolveRequestParameter(context, OAuth20Constants.RESPONSE_TYPE)

View on GitHub (pinned to e7288fc434)