apereo/cas · error

Unable to resolve federated service

Error message

Unable to resolve federated service [{}]

What it means

OpenIdFederationAuthorizationCodeResponseTypeAuthorizationRequestValidator.resolveAndSaveFederatedService failed to resolve a federated OP/client from its entity ID via trust-chain resolution. The trust chain (entity statements from entity configuration endpoints) could not be validated or fetched, so no federated service is registered and the authorization request is rejected with 'Unable to resolve federated service [clientId]'.

Solutions

  1. Verify the client's entity configuration URL (https://host/.well-known/openid-federation) is reachable from CAS and returns a valid entity statement.
  2. Configure the CAS OIDC federation trust anchors so the entity's trust chain terminates at an accepted anchor.
  3. Register the relying party explicitly as a service if federation is not intended for it.
  4. Check logs for the underlying exception via LoggingUtils to distinguish network vs signature/trust failures.

Example fix

// before: entity unknown to any trust anchor
// cas.authn.oidc.federation.trust-anchors= (empty)
// after
// cas.authn.oidc.federation.trust-anchors=https://trusted-anchor.example.org/.well-known/openid-federation
Defensive patterns

Strategy: validation

Validate before calling

// Verify entity configuration reachability before relying on federation
URL u = URI.create("https://client.example.org/.well-known/openid-federation").toURL();
HttpURLConnection c = (HttpURLConnection) u.openConnection();
c.setConnectTimeout(5000);
if (c.getResponseCode() != 200) throw new IllegalStateException("Entity config unreachable");

Try / catch

// Trust-chain resolution can fail transiently
try {
    Optional<OAuthRegisteredService> svc = resolver.resolveTrustChains(clientId);
    svc.orElseThrow(() -> new IllegalArgumentException("Unresolvable federated client " + clientId));
} catch (Exception e) {
    LOGGER.warn("Federation resolution failed for {}", clientId, e);
}

Prevention

When it happens

Trigger: An authorization request arrives with a clientId that is not registered locally, so CAS calls resolveMissingFederatedService or refreshes a temporary federation service; oidcFederationTrustChainResolver.resolveTrustChains(clientId) throws or returns empty because the entity's .well-known/openid-federation endpoint is unreachable, the trust chain lacks a trust anchor, or signatures fail validation.

Common situations: Federation entity's entity configuration endpoint down or misconfigured DNS/TLS; trust anchors not configured in CAS to cover the entity; expired entity statement keys; trying federation without the federation feature properly enabled.

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/380ab0febef9b93d. Report an issue: GitHub.

Appendix: source

Thrown at support/cas-server-support-oidc-federation/src/main/java/org/apereo/cas/oidc/federation/validator/OpenIdFederationAuthorizationCodeResponseTypeAuthorizationRequestValidator.java:89

        if (!shouldRefreshTemporaryFederationService(registeredService)) {
            return registeredService;
        }
        val serviceLock = SERVICE_LOCKS.computeIfAbsent(clientId, key -> new ReentrantLock());
        serviceLock.lock();
        try {
            return resolveAndSaveFederatedService(clientId).orElse(registeredService);
        } finally {
            serviceLock.unlock();
        }
    }

    private Optional<OAuthRegisteredService> resolveAndSaveFederatedService(final String clientId) {
        try {
            val resolvedService = oidcFederationTrustChainResolver.resolveTrustChains(clientId);
            LOGGER.debug("Resolved service: [{}]", resolvedService);
            return resolvedService.map(service -> (OAuthRegisteredService) getServicesManager().save(service));
        } catch (final Exception e) {
            LoggingUtils.warn(LOGGER, "Unable to resolve federated service [" + clientId + "]", e);
            return Optional.empty();
        }
    }

    private static boolean shouldRefreshTemporaryFederationService(final OAuthRegisteredService registeredService) {
        if (!registeredService.getProperties().containsKey(OidcFederationDefaultTrustChainResolver.TEMPORARY_OPENIDFEDERATION_SERVICE)) {
            return false;
        }
        val expirationDate = registeredService.getExpirationPolicy().getExpirationDate();
        val expiration = DateTimeUtils.zonedDateTimeOf(expirationDate);
        val refresh = expiration.minus(SERVICE_EXPIRATION_REFRESH_WINDOW).isBefore(ZonedDateTime.now(Clock.systemUTC()));
        LOGGER.debug("Should refresh: [{}] upfront: [{}]", registeredService, refresh);
        return refresh;
    }

    private static boolean isFederatedEntityId(final String clientId) {
        if (StringUtils.isBlank(clientId)) {
            return false;

View on GitHub (pinned to e7288fc434)