apereo/cas · warning

Response type not authorized for service

Error message

Response type not authorized for service: [{}] not listed in supported response types: [{}]

What it means

DefaultOAuth20RequestParameterResolver.isAuthorizedResponseTypeForService() compares the request's response_type against the registered service's supportedResponseTypes. When the list is non-empty but does not contain the requested response type, it warns and returns false, so the OAuth request (e.g., authorize) is denied as the requested response type is not authorized for that service.

Solutions

  1. Add the response_type the client requests (e.g., "code") to the service's supportedResponseTypes.
  2. Ensure the client sends the response_type parameter on authorize requests.
  3. Reload the services registry after editing the definition.
  4. Audit each client app's expected flow (code vs implicit) and align service definitions accordingly.

Example fix

// before (service JSON)
"supportedResponseTypes": ["token"]
// after
"supportedResponseTypes": ["code", "token"]
Defensive patterns

Strategy: validation

Validate before calling

const responseType = params.response_type;
if (!responseType || !service.supportedResponseTypes?.some(t => t.toLowerCase() === responseType.toLowerCase())) {
  throw new Error(`response_type '${responseType}' not authorized for this service`);
}

Type guard

function isResponseTypeAuthorized(service, responseType) {
  return typeof responseType === 'string' &&
    Array.isArray(service.supportedResponseTypes) &&
    service.supportedResponseTypes.some(t => t.toLowerCase() === responseType.toLowerCase());
}

Prevention

When it happens

Trigger: An authorize/device request with response_type=code (or token/id_token variants) for a service whose supportedResponseTypes excludes that value, or the parameter is missing (resolves to empty string) while the list is non-empty.

Common situations: Service JSON defines supportedResponseTypes ["token"] but client requests code; response_type parameter omitted entirely by the client; service entry copied from another app with a narrower type list; CAS version upgrade enforcing response-type matching.

Related errors


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

Appendix: source

Thrown at support/cas-server-support-oauth-core-api/src/main/java/org/apereo/cas/support/oauth/web/DefaultOAuth20RequestParameterResolver.java:207

    @Override
    public boolean isAuthorizedGrantTypeForService(final WebContext context,
                                                   final OAuthRegisteredService registeredService) {
        val grantType = resolveRequestParameter(context, OAuth20Constants.GRANT_TYPE)
            .map(String::valueOf).orElse(StringUtils.EMPTY);
        return OAuth20RequestParameterResolver.isAuthorizedGrantTypeForService(grantType, registeredService);
    }

    @Override
    public boolean isAuthorizedResponseTypeForService(final WebContext context,
                                                      final OAuthRegisteredService registeredService) {
        if (registeredService.getSupportedResponseTypes() != null && !registeredService.getSupportedResponseTypes().isEmpty()) {
            val responseType = resolveRequestParameter(context, OAuth20Constants.RESPONSE_TYPE)
                .map(String::valueOf).orElse(StringUtils.EMPTY);
            if (registeredService.getSupportedResponseTypes().stream().anyMatch(s -> s.equalsIgnoreCase(responseType))) {
                return true;
            }
            LOGGER.warn("Response type not authorized for service: [{}] not listed in supported response types: [{}]",
                responseType, registeredService.getSupportedResponseTypes());
            return false;
        }
        LOGGER.warn("Registered service [{}] does not define any authorized/supported response types. "
            + "It is STRONGLY recommended that you authorize and assign response types to the service definition. "
            + "While just a warning for now, this behavior will be enforced by CAS in future versions.", registeredService.getName());
        return true;
    }

    @Override
    public Pair<String, String> resolveClientIdAndClientSecret(final CallContext callContext) {
        val extractor = new BasicAuthExtractor();
        val upcResult = extractor.extract(callContext);
        if (upcResult.isPresent()) {
            val upc = (UsernamePasswordCredentials) upcResult.get();
            return Pair.of(upc.getUsername(), upc.getPassword());
        }
        val clientId = resolveRequestParameter(callContext.webContext(), OAuth20Constants.CLIENT_ID)

View on GitHub (pinned to e7288fc434)