apereo/cas · error · IllegalArgumentException

Service with client id is configured to encrypt tokens, yet…

Error message

Service %s with client id %s is configured to encrypt tokens, yet no JSON web key is available to handle encryption

What it means

BaseOidcJsonWebKeyTokenSigningAndEncryptionService.getJsonWebKeyForEncryption throws this when a registered OIDC client is configured to receive encrypted tokens but no usable JSON web key can be resolved for the encryption step. If id-token encryption is optional (oidcService.isIdTokenEncryptionOptional()) CAS only logs and returns null; otherwise it fails hard.

Solutions

  1. Publish a valid JWKS at the client's registered jwks_uri containing a current encryption key
  2. Enable cas.authn.oidc.core.id-token-encryption-optional=true so encryption is skipped (logged) instead of failing
  3. Check the CAS JWK keystore rotation state so at least one key is in the CURRENT state
  4. Verify the JWKS URI is reachable from the CAS server (network/TLS/firewall)

Example fix

// before (cas.properties)
cas.authn.oidc.core.id-token-encryption-optional=false
// after (make encryption best-effort)
cas.authn.oidc.core.id-token-encryption-optional=true
// or fix the client's JWKS so a current key exists
Defensive patterns

Strategy: try-catch

Validate before calling

var jwks = fetchJwks(client.getJwksUri());
if (jwks == null || jwks.getJsonWebKeys().stream().noneMatch(k -> "current".equals(stateOf(k)))) {
    throw new IllegalStateException("Client " + client.getClientId() + " has no current encryption key in JWKS");
}

Try / catch

try { return encryptionService.encrypt(token, service); } catch (IllegalArgumentException e) { if (e.getMessage().contains("no JSON web key")) { log.warn("Skipping encryption for {}", service.getClientId()); return unencrypted(token); } throw e; }

Prevention

When it happens

Trigger: encryptionKey() runs for a service with encryption enabled, but the client's JWKS is absent/unfetchable, contains no keys in the 'current' lifecycle state, or no key matches the required use/algorithm; and cas.authn.oidc.core.id-token-encryption-optional=false.

Common situations: Client did not publish a JWKS at its registered jwks_uri; all keys in the rotation store are expired/retired; JWKS fetch fails (network, TLS); server upgraded with token encryption now mandatory.

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/450e690530b1a0c3. Report an issue: GitHub.

Appendix: source

Thrown at support/cas-server-support-oidc-core-api/src/main/java/org/apereo/cas/oidc/token/BaseOidcJsonWebKeyTokenSigningAndEncryptionService.java:137

            .flatMap(Optional::stream)
            .findFirst();

        LOGGER.debug("Located key [{}] for service [{}]", finalKey, serviceResult);
        return finalKey.orElseGet(() -> (PublicJsonWebKey) jsonWebKeys.getFirst());
    }

    protected @Nullable PublicJsonWebKey getJsonWebKeyForEncryption(final OAuthRegisteredService registeredService) {
        LOGGER.debug("Service [{}] is set to encrypt tokens", registeredService);
        val oidcService = (OidcRegisteredService) registeredService;
        val jwks = serviceJsonWebKeystoreCache.get(new OidcJsonWebKeyCacheKey(registeredService, OidcJsonWebKeyUsage.ENCRYPTION));
        if (jwks.isEmpty()) {
            val message = "Service %s with client id %s is configured to encrypt tokens, yet no JSON web key is available to handle encryption"
                .formatted(registeredService.getServiceId(), registeredService.getClientId());
            if (oidcService.isIdTokenEncryptionOptional()) {
                LOGGER.info(message);
                return null;
            }
            throw new IllegalArgumentException(message);
        }
        val jsonWebKey = jwks.get()
            .getJsonWebKeys()
            .stream()
            .filter(key -> OidcJsonWebKeystoreRotationService.JsonWebKeyLifecycleStates.getJsonWebKeyState(key).isCurrent())
            .min(Comparator.comparing(JsonWebKey::getKeyId))
            .orElseThrow(() -> new IllegalArgumentException("Cannot locate current JSON web key for encryption"));
        LOGGER.debug("Found JSON web key to encrypt the token: [{}]", jsonWebKey);
        Objects.requireNonNull(jsonWebKey.getKey(), "JSON web key used to encrypt the token has no associated public key");
        return (PublicJsonWebKey) jsonWebKey;
    }
}

View on GitHub (pinned to e7288fc434)