apereo/cas · warning

Registered service access is not allowed for service…

Error message

Registered service access is not allowed for service definition for client id [{}]

What it means

OAuth20DeviceCodeResponseTypeRequestValidator.validate() rejects the device-authorization request when the registered OAuth service cannot be accessed or when neither the response type nor the grant type is authorized for the client. Any exception thrown by ensureServiceAccessIsAllowed (or the validator chain) is caught and converted into this warning and a `false` result, so the device code flow is denied early.

Solutions

  1. Inspect the registered service definition for the given clientId in the services registry (JSON/JDBC/etc.) and confirm the access strategy allows access (enabled, not expired, valid IP/environment).
  2. Add the device-code response type and grant type to the service's supportedResponseTypes/supportedGrantTypes lists.
  3. If access should be denied intentionally, no action: CAS correctly rejects it; fix the client to use a registered, authorized clientId.
  4. Reload/redeploy the service registry after edits so ServicesManager picks up the new definition.

Example fix

// before (service JSON)
"supportedGrantTypes": [],
"supportedResponseTypes": []
// after
"supportedGrantTypes": ["urn:ietf:params:oauth:grant-type:device_code"],
"supportedResponseTypes": ["device_token"]
Defensive patterns

Strategy: validation

Validate before calling

// before calling the device endpoint, verify service access in the registry
const svc = services.find(s => s.clientId === clientId);
if (!svc || !svc.enabled || new Date(svc.expirationDate) < new Date()) {
  throw new Error(`Service for clientId ${clientId} is not accessible`);
}
if (!svc.supportedGrantTypes.includes('urn:ietf:params:oauth:grant-type:device_code')) {
  throw new Error('device_code grant not authorized for service');
}

Type guard

function isAccessibleService(svc) {
  return !!svc && svc.enabled === true &&
    (!svc.expirationDate || new Date(svc.expirationDate) > new Date());
}

Prevention

When it happens

Trigger: A device-authorization request arrives with a clientId whose registered service is disabled, expired, outside its valid date window, or lacks access from the client's IP address; alternatively the service does not authorize the requested response type/grant type and neither `validResponseType` nor `validGrantType` evaluates true.

Common situations: Service definition created but left `enabled: false` or with an expiration date in the past; environment/IP allowlist restrictions on the service; supportedResponseTypes or supportedGrantTypes not configured on the service definition; wrong clientId sent by the device client.

Understand the failure class

Background: Permission denied / not authorized / 403 Forbidden: access-control rejections when the caller lacks the required role, grant, or ownership — this error's family across 18 libraries.

Related errors


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

            .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)
            .map(String::valueOf).orElse(StringUtils.EMPTY);
        val grantType = requestParameterResolver.resolveRequestParameter(context, OAuth20Constants.GRANT_TYPE)
            .map(String::valueOf).orElse(StringUtils.EMPTY);
        val clientId = requestParameterResolver.resolveRequestParameter(context, OAuth20Constants.CLIENT_ID)
            .map(String::valueOf).orElse(StringUtils.EMPTY);
        val validRequest = OAuth20Utils.isResponseType(responseType, OAuth20ResponseTypes.DEVICE_CODE)
                           || OAuth20Utils.isGrantType(grantType, OAuth20GrantTypes.DEVICE_CODE);
        return validRequest && StringUtils.isNotBlank(clientId);
    }
}

View on GitHub (pinned to e7288fc434)