In Keycloak 21.0.0, an issue occurs during signature verification when consuming an external API that provides JSON Web Keys (JWKs). The system fails to find the expected public key, logging the following warning and error messages:
WARN [org.keycloak.keys.infinispan.InfinispanPublicKeyStorageProvider] PublicKey wasn’t found in the storage. Requested kid: ‘sig-2024-10-07-DB’. Available kids: ‘’ WARN [org.keycloak.services] KC-SERVICES0097: Invalid request: java.lang.RuntimeException: Failed to verify signature on ‘request’ object
@Override
public void authenticate(AuthenticationFlowContext context) {
JWKSet euroInfoJwkSet = fetchJWKSet();
boolean isValid = verifySignature(decryptedJwt, euroInfoJwkSet);
if (!isValid) {
context.failure(GENERIC_AUTHENTICATION_ERROR);
return;
}
}
private JWKSet fetchJWKSet() throws Exception {
URL url = new URL(“https://request/jwk_request.cgi?client_id=5g4h4r8r”);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod(“GET”);
conn.setRequestProperty(“Accept”, “application/json”);
if (conn.getResponseCode() != 200) {
throw new RuntimeException("Failed to fetch JWKs: HTTP error code " + conn.getResponseCode());
}
BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
StringBuilder response = new StringBuilder();
String inputLine;
while ((inputLine = in.readLine()) != null) {
response.append(inputLine);
}
in.close();
Gson gson = new Gson();
return JWKSet.parse(response.toString());
}
private boolean verifySignature(String jwt, JWKSet euroInfoJwkSet) throws Exception {
String jwtParts = jwt.split(“\.”);
if (jwtParts.length != 3) {
throw new IllegalArgumentException(“Invalid JWT format”);
}
byte[] signatureBytes = Base64.getUrlDecoder().decode(jwtParts[2]);
JWK jwk = euroInfoJwkSet.getKeyByKeyId(jwtParts[0]);
PublicKey publicKey = ((RSAKey) jwk).toPublicKey();
Signature sig = Signature.getInstance("SHA256withRSA");
sig.initVerify(publicKey);
sig.update((jwtParts[0] + "." + jwtParts[1]).getBytes());
return sig.verify(signatureBytes);
}