apereo/cas · error
No valid JSON web keys used for encryption can be found
Error message
No valid JSON web keys used for encryption can be found
What it means
This warning is logged by OidcJsonWebKeyStoreUtils.fetchJsonWebKeySetForEncryption when a JWKS entry exists in the encryption keystore cache, but every contained key fails the key.getKey() != null filter — i.e. the JsonWebKey entries carry no usable Key material. The method returns Optional.empty() so no encryption key set is produced.
Solutions
- Validate the JWKS JSON contains complete key parameters for each key type (n+e for RSA, x+y+crv for EC, k for oct) and fix or regenerate it
- Use jose4j or a JWKS validator to parse the JWKS and confirm each key yields non-null getKey() before publishing it
- Re-export the keys from the original keystore (e.g. JWK from KeyStore conversion) instead of hand-authoring the JSON
- If the cached entry is stale/broken, invalidate the registered-service JWKS cache and reload from a corrected source
Example fix
// before: incomplete RSA enc key in JWKS
{"keys":[{"kty":"RSA","use":"enc","kid":"rp-enc-1"}]}
// after: include full public key material
{"keys":[{"kty":"RSA","use":"enc","kid":"rp-enc-1","n":"0vx7...","e":"AQAB"}]} Defensive patterns
Strategy: validation
Validate before calling
// Validate the JWKS fully parses into keys with real key material
JsonWebKeySet jwks = new JsonWebKeySet(jwksJson);
List<JsonWebKey> usable = jwks.getJsonWebKeys().stream()
.filter(k -> k.getKey() != null).toList();
if (usable.isEmpty()) {
throw new IllegalStateException("JWKS parses but no keys carry key material "
+ "(check n/e for RSA, x/y/crv for EC, k for oct)");
} Type guard
static boolean allKeysHaveMaterial(JsonWebKeySet jwks) {
return !jwks.getJsonWebKeys().isEmpty()
&& jwks.getJsonWebKeys().stream().allMatch(k -> k.getKey() != null);
} Try / catch
try {
Optional<JsonWebKeySet> keys =
OidcJsonWebKeyStoreUtils.fetchJsonWebKeySetForEncryption(service, cipherExecutor);
if (keys.isEmpty()) {
LOG.warn("Cached enc JWKS has no usable key material for {}", service.getClientId());
}
} catch (Exception e) {
LOG.error("Failed to build encryption key set", e);
} Prevention
- Never hand-author JWKS JSON; export keys programmatically (e.g. jose4j PublicJsonWebKey.toJson) so all parameters are present
- Run a JWKS lint/parse step in CI before publishing keys
- Diff published JWKS against the source keystore after edits
- Invalidate the JWKS cache after replacing a malformed key so the fixed version is reloaded
When it happens
Trigger: Calling fetchJsonWebKeySetForEncryption with a cached JsonWebKeySet whose parsed keys are PublicJsonWebKey instances without a resolvable java.security.Key (e.g. JWKS JSON missing required parameters like 'n'/'e' for RSA or 'x'/'y' for EC, or oct keys missing 'k'), so jose4j constructs JWKs with null Key objects.
Common situations: Hand-edited or truncated JWKS files published by the relying party; JWKS JSON that parses as valid JSON but with malformed/missing key parameters; keys serialized without key material (public-only placeholders); encoding errors in base64url parameters.
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
Related errors
- Service with client id is configured to encrypt tokens, yet…
- Service [ ] with client id [ ] is configured to encrypt…
- JWKS cannot contain expressions
- Unable to use 'none' as introspection encryption algorithm
- Unable to use 'none' as user-info encryption algorithm
AI-assisted analysis of apereo/cas@e7288fc434 (2026-09-08).
Data as JSON: /api/errors/f2b339238a88f6e7.
Report an issue: GitHub.
Appendix: source
Thrown at support/cas-server-support-oidc-core-api/src/main/java/org/apereo/cas/oidc/jwks/OidcJsonWebKeyStoreUtils.java:285
* @param cipherExecutor the cipher executor
* @return the optional
*/
public static Optional<JsonWebKeySet> fetchJsonWebKeySetForEncryption(final RegisteredService registeredService,
final OidcRegisteredServiceJwtCipherExecutor cipherExecutor) {
val oidcRegisteredService = (OidcRegisteredService) registeredService;
val jwks = Objects.requireNonNull(cipherExecutor.getRegisteredServiceJsonWebKeystoreCache().get(
new OidcJsonWebKeyCacheKey(oidcRegisteredService, OidcJsonWebKeyUsage.ENCRYPTION)));
if (jwks.isEmpty()) {
LOGGER.warn("Service [{}] with client id [{}] is configured to encrypt tokens, yet no JSON web key is available",
oidcRegisteredService.getServiceId(), oidcRegisteredService.getClientId());
return Optional.empty();
}
val jsonWebKey = jwks.get();
LOGGER.debug("Found JSON web key to encrypt the token: [{}]", jsonWebKey);
val keys = jsonWebKey.getJsonWebKeys().stream().filter(key -> key.getKey() != null).toList();
if (keys.isEmpty()) {
LOGGER.warn("No valid JSON web keys used for encryption can be found");
return Optional.empty();
}
return Optional.of(new JsonWebKeySet(keys));
}
}
View on GitHub (pinned to e7288fc434)