{"record":{"id":"06235c5714af6e25","repo":"apereo/cas","slug":"unable-to-locate-json-web-key-for","errorCode":null,"errorMessage":"Unable to locate JSON web key for [{}]","messagePattern":"Unable to locate JSON web key for \\[(.+?)\\]","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"support/cas-server-support-oidc-core-api/src/main/java/org/apereo/cas/oidc/jwks/OidcJsonWebKeyStoreUtils.java","lineNumber":95,"sourceCode":"     * @param jwks         the jwks\n     * @param requestedKey the kid\n     * @param usage        the usage\n     * @return the json web key from jwks\n     */\n    public static Optional<JsonWebKeySet> getJsonWebKeyFromJsonWebKeySet(\n        final JsonWebKeySet jwks, final Optional<String> requestedKey, final Optional<OidcJsonWebKeyUsage> usage) {\n        if (jwks.getJsonWebKeys().isEmpty()) {\n            LOGGER.warn(\"No JSON web keys are available in the keystore\");\n            return Optional.empty();\n        }\n\n        val keyResult = getJsonWebKeyByKeyId(jwks, requestedKey, usage)\n            .getJsonWebKeys()\n            .stream()\n            .filter(key -> key.getKey() != null)\n            .collect(Collectors.toList());\n        if (keyResult.isEmpty()) {\n            LOGGER.warn(\"Unable to locate JSON web key for [{}]\", requestedKey.map(Object::toString));\n            return Optional.empty();\n        }\n        return Optional.of(new JsonWebKeySet(keyResult));\n    }\n\n    private static List<JsonWebKey> filterJsonWebKeySetKeysBy(final JsonWebKeySet jwks,\n                                                              final Optional<String> keyIdRequest,\n                                                              final Optional<OidcJsonWebKeyUsage> usage) {\n\n        var filter = (Predicate<JsonWebKey>) PublicJsonWebKey.class::isInstance;\n        if (keyIdRequest.isPresent()) {\n            filter = filter.and(jsonWebKey -> Strings.CI.equals(jsonWebKey.getKeyId(), keyIdRequest.get()));\n        }\n        if (usage.isPresent()) {\n            filter = filter.and(jsonWebKey -> usage.get().is(jsonWebKey));\n        }\n        return jwks.getJsonWebKeys()\n            .stream()","sourceCodeStart":77,"sourceCodeEnd":113,"githubUrl":"https://github.com/apereo/cas/blob/e7288fc434b4f4505b8452e1a57e8fb3111bb863/support/cas-server-support-oidc-core-api/src/main/java/org/apereo/cas/oidc/jwks/OidcJsonWebKeyStoreUtils.java#L77-L113","documentation":"This warning is logged by OidcJsonWebKeyStoreUtils.getJsonWebKeyFromJsonWebKeySet when, after filtering a parsed JWKS by the requested key id (kid) and/or key usage, no key with a non-null key material remains. The method returns Optional.empty(), so callers silently receive no key set. It means the keystore exists and parses, but does not contain a key matching the service's configured jwksKeyId/usage.","triggerScenarios":"Calling getJsonWebKeySet for an OidcRegisteredService whose jwksKeyId does not match any kid in the JWKS file/inline JSON, or whose keys lack the requested usage (use=sign/enc), or whose matched keys have null key material (e.g. only private or only public parts available). Also triggered when the service's jwks value is not valid JSON and is instead treated as a raw AES secret with a mismatching kid/usage.","commonSituations":"Rotating JWKS on the service side but forgetting to update cas.serviceRegistry OidcRegisteredService.jwksKeyId; copying a public-only JWKS while tokens require the private key; a key with a missing or wrong 'use' claim; typo in the kid string in the service registry entry.","solutions":["Compare the jwksKeyId set on the OidcRegisteredService with the kid values actually present in the JWKS JSON and correct the mismatch","Regenerate or edit the JWKS so it contains a PublicJsonWebKey with the expected kid, usage, and key material","If no specific kid is needed, clear jwksKeyId on the service so any valid key matches","Ensure the resource at the service's jwks URL/path is valid JWKS JSON; if it is a plain secret string, verify the derived kid/usage expectations"],"exampleFix":"// before: service registry entry\n\"@class\":\"org.apereo.cas.services.OidcRegisteredService\",\n\"jwks\":\"https://rp.example.com/jwks.json\",\n\"jwksKeyId\":\"old-rotated-kid\"\n// after\n\"@class\":\"org.apereo.cas.services.OidcRegisteredService\",\n\"jwks\":\"https://rp.example.com/jwks.json\",\n\"jwksKeyId\":\"current-kid-2026\"","handlingStrategy":"validation","validationCode":"// Before relying on a service's JWKS, parse and check a matching key exists\nJsonWebKeySet jwks = new JsonWebKeySet(jwksJson);\nboolean hasUsableKey = jwks.getJsonWebKeys().stream()\n    .anyMatch(k -> k instanceof PublicJsonWebKey\n        && (serviceJwksKeyId == null || serviceJwksKeyId.equalsIgnoreCase(k.getKeyId()))\n        && k.getKey() != null);\nif (!hasUsableKey) {\n    throw new IllegalStateException(\"JWKS has no key matching kid=\" + serviceJwksKeyId);\n}","typeGuard":"static boolean hasUsableKeyFor(JsonWebKeySet jwks, String kid) {\n    return jwks.getJsonWebKeys().stream().anyMatch(k ->\n        k instanceof PublicJsonWebKey\n            && (kid == null || kid.equalsIgnoreCase(k.getKeyId()))\n            && k.getKey() != null);\n}","tryCatchPattern":"try {\n    return OidcJsonWebKeyStoreUtils.getJsonWebKeySet(service, resourceLoader, usage);\n} catch (Exception e) {\n    LOG.error(\"JWKS lookup failed for service {}\", service.getClientId(), e);\n    return Optional.empty();\n}","preventionTips":["Keep jwksKeyId on the service in sync with the kid published in the JWKS; update both together when rotating","Validate the JWKS JSON with jose4j at deploy time and in CI before it is published","Include both signing (use=sign) and encryption (use=enc) keys in the RP JWKS as needed","Prefer letting CAS generate and manage the keystore rather than hand-editing JWKS files"],"tags":["oidc","jwks","key-not-found","kid-mismatch"],"backgroundTag":"record-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"}