apereo/cas · error · UnauthorizedServiceException

Denied

Error message

Denied: %s

What it means

Delegated client lookup failed: findDelegatedClientByName in DelegatedClientAuthenticationAction cannot resolve the requested identity-provider client name against the pac4j IdentityProviders configuration, so CAS denies access with an UnauthorizedServiceException. This guards against requests naming an unconfigured or unauthorized provider.

Solutions

  1. Verify the clientName parameter matches a pac4j client registered in cas.authn.pac4j.* configuration
  2. Check that no service-level filter (unauthorized redirection policy / custom Authorizer) is excluding the client
  3. Confirm the DelegatedClientIdentityProviderConfigurationFactory includes the client for the requested service
  4. Enable debug logging for org.apereo.cas.support.pac4j.web.flow to see why the client set is empty

Example fix

// before
cas.authn.pac4j.oidc[0].client-name = GitHUB
// after (matches the name used in the request)
cas.authn.pac4j.oidc[0].client-name = GitHubClient
Defensive patterns

Strategy: validation

Validate before calling

if (cas.getIdentityProviders().findClient(clientName, webContext).isEmpty()) {
    // route to an error event instead of invoking the action
}

Try / catch

try { ... } catch (UnauthorizedServiceException e) { return errorEvent("delegationDenied", e); }

Prevention

When it happens

Trigger: A request parameter (e.g. client_name) names a delegated client that is not registered in the DelegatedClientIdentityProviderConfigurationFactory results, is filtered out as unauthorized for the service, or findClient returns empty for the given JEEContext.

Common situations: Typo in the client name in links or service config; client disabled by an AuthorizationGenerator/service filter; config change after CAS restart removed the provider; user bookmarked an old SSO link.

Understand the failure class

Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.

Related errors


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

Appendix: source

Thrown at support/cas-server-support-pac4j-webflow/src/main/java/org/apereo/cas/web/flow/actions/DelegatedClientAuthenticationAction.java:266

    protected Optional<ClientCredential> populateContextWithClientCredential(final BaseClient client,
                                                                             final RequestContext requestContext) {
        return configContext.getCredentialExtractors()
            .stream()
            .filter(BeanSupplier::isNotProxy)
            .map(extractor -> extractor.extract(client, requestContext))
            .flatMap(Optional::stream)
            .findFirst();
    }

    protected BaseClient findDelegatedClientByName(final String clientName, final RequestContext context) {
        val request = WebUtils.getHttpServletRequestFromExternalWebflowContext(context);
        val response = WebUtils.getHttpServletResponseFromExternalWebflowContext(context);
        
        val webContext = new JEEContext(request, response);
        val clientResult = configContext.getIdentityProviders().findClient(clientName, webContext);
        if (clientResult.isEmpty()) {
            LOGGER.warn("Delegated client [{}] can not be located", clientName);
            throw UnauthorizedServiceException.denied("Denied: %s".formatted(clientName));
        }
        val client = (BaseClient) clientResult.get();
        client.init();
        return client;
    }

    private void verifyClientIsAuthorizedForService(final RequestContext requestContext, @Nullable final Service service, final BaseClient client) {
        LOGGER.debug("Delegated authentication client is [{}] with service [{}]", client, service);
        if (service != null) {
            val request = WebUtils.getHttpServletRequestFromExternalWebflowContext(requestContext);
            request.setAttribute(CasProtocolConstants.PARAMETER_SERVICE, service);
        }
        if (!isDelegatedClientAuthorizedForService(client, service, requestContext)) {
            LOGGER.error("Delegated client [{}] is not authorized by service [{}]", client, service);
            throw UnauthorizedServiceException.denied("Denied: %s".formatted(service));
        }
    }

View on GitHub (pinned to e7288fc434)