{"record":{"id":"2933955ff3c0b41c","repo":"apereo/cas","slug":"unable-to-successfully-fetch-jwks-resource-from","errorCode":null,"errorMessage":"Unable to successfully fetch JWKS resource from [{}]","messagePattern":"Unable to successfully fetch JWKS resource from \\[(.+?)\\]","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"support/cas-server-support-oidc-core-api/src/main/java/org/apereo/cas/oidc/jwks/generator/OidcRestfulJsonWebKeystoreGeneratorService.java","lineNumber":56,"sourceCode":"    @Override\n    public Optional<Resource> find() throws Exception {\n        return Optional.ofNullable(generate());\n    }\n\n    @Override\n    public @Nullable Resource generate() throws Exception {\n        val rest = oidcProperties.getJwks().getRest();\n        val exec = HttpExecutionRequest.builder()\n            .basicAuthPassword(rest.getBasicAuthPassword())\n            .basicAuthUsername(rest.getBasicAuthUsername())\n            .maximumRetryAttempts(rest.getMaximumRetryAttempts())\n            .method(HttpMethod.GET)\n            .headers(rest.getHeaders())\n            .url(rest.getUrl())\n            .build();\n        val response = HttpUtils.execute(exec);\n        if (response == null || !HttpStatus.valueOf(response.getCode()).is2xxSuccessful()) {\n            LOGGER.warn(\"Unable to successfully fetch JWKS resource from [{}]\", rest.getUrl());\n            return null;\n        }\n\n        try (val content = ((HttpEntityContainer) response).getEntity().getContent()) {\n            val result = IOUtils.toString(content, StandardCharsets.UTF_8);\n            LOGGER.debug(\"Received payload result from [{}] as [{}]\", rest.getUrl(), result);\n            return new ByteArrayResource(result.getBytes(StandardCharsets.UTF_8), \"OIDC JWKS\");\n        }\n    }\n\n    @Override\n    public JsonWebKeySet store(final JsonWebKeySet jsonWebKeySet) {\n        val rest = oidcProperties.getJwks().getRest();\n        val headers = CollectionUtils.<String, String>wrap(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);\n        headers.putAll(rest.getHeaders());\n        val exec = HttpExecutionRequest.builder()\n            .basicAuthPassword(rest.getBasicAuthPassword())\n            .basicAuthUsername(rest.getBasicAuthUsername())","sourceCodeStart":38,"sourceCodeEnd":74,"githubUrl":"https://github.com/apereo/cas/blob/e7288fc434b4f4505b8452e1a57e8fb3111bb863/support/cas-server-support-oidc-core-api/src/main/java/org/apereo/cas/oidc/jwks/generator/OidcRestfulJsonWebKeystoreGeneratorService.java#L38-L74","documentation":"This warning is logged by OidcRestfulJsonWebKeystoreGeneratorService.generate when the HTTP GET to the configured cas.authn.oidc.jwks.rest.url fails: HttpUtils.execute returns null (connection failure, timeout, exhausted retries) or the response status is not 2xx. The method returns null, meaning no JWKS resource could be fetched from the REST endpoint.","triggerScenarios":"generate()/find() is invoked while the REST JWKS endpoint is down or unreachable, returns 401/403 due to wrong basic-auth credentials (basicAuthUsername/basicAuthPassword), returns 404/500, or the configured URL is wrong; retries configured via maximumRetryAttempts are exhausted.","commonSituations":"External JWKS store service not yet started when CAS boots; misconfigured cas.authn.oidc.jwks.rest.url (typo, wrong host/port, TLS certificate not trusted); incorrect basic auth credentials; firewall/proxy blocking the request; endpoint returning 401 after a credential rotation.","solutions":["Verify cas.authn.oidc.jwks.rest.url is correct and the endpoint is reachable from the CAS server (curl the URL and expect a 2xx JWKS body)","Check/fix the basic auth username and password configured for the REST JWKS endpoint","Inspect the endpoint's server logs for the failing status (404/401/500) and fix the server-side cause","If the endpoint is intermittently unavailable, raise maximumRetryAttempts or add a fallback JWKS file configuration"],"exampleFix":"# before: wrong credentials/URL\ncas.authn.oidc.jwks.rest.url=https://jwks.internal.example.com/wrong-path\ncas.authn.oidc.jwks.rest.basic-auth-username=stale-user\n# after\ncas.authn.oidc.jwks.rest.url=https://jwks.internal.example.com/jwks\ncas.authn.oidc.jwks.rest.basic-auth-username=svc-cas\ncas.authn.oidc.jwks.rest.basic-auth-password=<current-secret>","handlingStrategy":"retry","validationCode":"// Before configuring the REST JWKS source, verify it serves a 2xx JWKS\nHttpRequest request = HttpRequest.newBuilder(URI.create(restUrl)).GET().build();\nHttpResponse<String> resp = client.send(request, HttpResponse.BodyHandlers.ofString());\nif (resp.statusCode() / 100 != 2) {\n    throw new IllegalStateException(\"JWKS REST endpoint \" + restUrl\n        + \" returned HTTP \" + resp.statusCode());\n}","typeGuard":"static boolean isReachableJwksEndpoint(String url) {\n    try {\n        var exec = HttpExecutionRequest.builder().method(HttpMethod.GET).url(url).build();\n        var response = HttpUtils.execute(exec);\n        return response != null && HttpStatus.valueOf(response.getCode()).is2xxSuccessful();\n    } catch (Exception e) {\n        return false;\n    }\n}","tryCatchPattern":"try {\n    Optional<Resource> jwks = generatorService.find();\n    if (jwks.isEmpty()) {\n        LOG.warn(\"REST JWKS source unavailable; falling back to file-based JWKS\");\n        return fileBasedJwksResource();\n    }\n    return jwks;\n} catch (Exception e) {\n    LOG.error(\"JWKS fetch from REST failed\", e);\n    return Optional.empty();\n}","preventionTips":["Health-check the JWKS REST endpoint before and during CAS startup; delay JWKS loading until it is up","Verify basic-auth credentials and URL with curl before wiring them into cas.authn.oidc.jwks.rest.*","Increase cas.authn.oidc.jwks.rest.maximum-retry-attempts for flaky networks","Keep a file-based JWKS fallback so OIDC survives transient REST outages","Ensure TLS trust for the endpoint's certificate is present in the CAS JVM truststore"],"tags":["http","network","jwks","rest"],"backgroundTag":"http-request-failed","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"}