{"record":{"id":"450e690530b1a0c3","repo":"apereo/cas","slug":"service-s-with-client-id-s-is-configured-to-encr","errorCode":null,"errorMessage":"Service %s with client id %s is configured to encrypt tokens, yet no JSON web key is available to handle encryption","messagePattern":"Service (.+?) with client id (.+?) is configured to encrypt tokens, yet no JSON web key is available to handle encryption","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"support/cas-server-support-oidc-core-api/src/main/java/org/apereo/cas/oidc/token/BaseOidcJsonWebKeyTokenSigningAndEncryptionService.java","lineNumber":137,"sourceCode":"            .flatMap(Optional::stream)\n            .findFirst();\n\n        LOGGER.debug(\"Located key [{}] for service [{}]\", finalKey, serviceResult);\n        return finalKey.orElseGet(() -> (PublicJsonWebKey) jsonWebKeys.getFirst());\n    }\n\n    protected @Nullable PublicJsonWebKey getJsonWebKeyForEncryption(final OAuthRegisteredService registeredService) {\n        LOGGER.debug(\"Service [{}] is set to encrypt tokens\", registeredService);\n        val oidcService = (OidcRegisteredService) registeredService;\n        val jwks = serviceJsonWebKeystoreCache.get(new OidcJsonWebKeyCacheKey(registeredService, OidcJsonWebKeyUsage.ENCRYPTION));\n        if (jwks.isEmpty()) {\n            val message = \"Service %s with client id %s is configured to encrypt tokens, yet no JSON web key is available to handle encryption\"\n                .formatted(registeredService.getServiceId(), registeredService.getClientId());\n            if (oidcService.isIdTokenEncryptionOptional()) {\n                LOGGER.info(message);\n                return null;\n            }\n            throw new IllegalArgumentException(message);\n        }\n        val jsonWebKey = jwks.get()\n            .getJsonWebKeys()\n            .stream()\n            .filter(key -> OidcJsonWebKeystoreRotationService.JsonWebKeyLifecycleStates.getJsonWebKeyState(key).isCurrent())\n            .min(Comparator.comparing(JsonWebKey::getKeyId))\n            .orElseThrow(() -> new IllegalArgumentException(\"Cannot locate current JSON web key for encryption\"));\n        LOGGER.debug(\"Found JSON web key to encrypt the token: [{}]\", jsonWebKey);\n        Objects.requireNonNull(jsonWebKey.getKey(), \"JSON web key used to encrypt the token has no associated public key\");\n        return (PublicJsonWebKey) jsonWebKey;\n    }\n}\n","sourceCodeStart":119,"sourceCodeEnd":150,"githubUrl":"https://github.com/apereo/cas/blob/e7288fc434b4f4505b8452e1a57e8fb3111bb863/support/cas-server-support-oidc-core-api/src/main/java/org/apereo/cas/oidc/token/BaseOidcJsonWebKeyTokenSigningAndEncryptionService.java#L119-L150","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Publish a valid JWKS at the client's registered jwks_uri containing a current encryption key","Enable cas.authn.oidc.core.id-token-encryption-optional=true so encryption is skipped (logged) instead of failing","Check the CAS JWK keystore rotation state so at least one key is in the CURRENT state","Verify the JWKS URI is reachable from the CAS server (network/TLS/firewall)"],"exampleFix":"// before (cas.properties)\ncas.authn.oidc.core.id-token-encryption-optional=false\n// after (make encryption best-effort)\ncas.authn.oidc.core.id-token-encryption-optional=true\n// or fix the client's JWKS so a current key exists","handlingStrategy":"try-catch","validationCode":"var jwks = fetchJwks(client.getJwksUri());\nif (jwks == null || jwks.getJsonWebKeys().stream().noneMatch(k -> \"current\".equals(stateOf(k)))) {\n    throw new IllegalStateException(\"Client \" + client.getClientId() + \" has no current encryption key in JWKS\");\n}","typeGuard":null,"tryCatchPattern":"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; }","preventionTips":["Verify each encryption-enabled client publishes a reachable JWKS with a current key","Monitor JWKS fetch failures in CAS logs","Set id-token-encryption-optional=true if encryption is best-effort"],"tags":["oidc","jwks","encryption","configuration"],"backgroundTag":"resource-not-found","analyzedSha":"e7288fc434b4f4505b8452e1a57e8fb3111bb863","analyzedAt":"2026-09-08T15:39:16.015Z","contentChangedAt":"2026-09-08T15:39:16.015Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}