apache/pulsar · error · AuthenticationException
Malformed JWKS returned by:
Error message
Malformed JWKS returned by:
What it means
JwksCache.convertToJwks() expects the fetched JWKS document to be a JSON object with a "keys" member holding an array of key objects (RFC 7517 section 5.1). If casting the parsed document's "keys" value to List<Map<String,Object>> throws ClassCastException — e.g. "keys" is missing (null), not a list, or contains non-map entries — the method rethrows it as AuthenticationException("Malformed JWKS returned by: <uri>").
Source
Thrown at pulsar-broker-auth-oidc/src/main/java/org/apache/pulsar/broker/authentication/oidc/JwksCache.java:243
/**
* The JWK Set is stored in the "keys" key see https://www.rfc-editor.org/rfc/rfc7517#section-5.1.
*
* @param jwksUri - the URI used to retrieve the JWKS
* @param jwks - the JWKS to convert
* @return a list of {@link Jwk}
*/
private List<Jwk> convertToJwks(String jwksUri, Map<String, Object> jwks) throws AuthenticationException {
try {
@SuppressWarnings("unchecked")
List<Map<String, Object>> jwkList = (List<Map<String, Object>>) jwks.get("keys");
final List<Jwk> result = new ArrayList<>();
for (Map<String, Object> jwk : jwkList) {
result.add(Jwk.fromValues(jwk));
}
return result;
} catch (ClassCastException e) {
throw new AuthenticationException("Malformed JWKS returned by: " + jwksUri);
}
}
}
View on GitHub (pinned to 820761864e)
Solutions
- Fetch the configured jwksUri with curl and verify it is a JWK Set: {"keys":[{...}]} with each key an object containing kty etc.
- Correct the jwks_uri configuration — it must point to the JWKS endpoint, not the discovery document or an HTML page.
- Check for proxies/ingress returning error bodies with 200 status, and bypass or fix them.
- If the IdP is non-standard, ensure its keyset endpoint conforms to RFC 7517 before connecting it.
Example fix
// before (wrong endpoint configured) ownedTenant="https://idp.example.com/.well-known/openid-configuration" // after (actual JWKS endpoint) jwksUri=https://idp.example.com/.well-known/jwks.json
Defensive patterns
Strategy: validation
Validate before calling
curl -fsSL "$JWKS_URI" | jq -e '(.keys | type) == "array" and (.keys | length) > 0 and (.keys[0] | type) == "object"' >/dev/null \ && echo OK || echo "Not a valid JWK Set"
Try / catch
try {
List<Jwk> jwks = fetchAndConvert(jwksUri);
} catch (AuthenticationException e) {
if (e.getMessage().startsWith("Malformed JWKS returned by")) {
// verify endpoint config / check for proxy-injected error bodies
}
} Prevention
- Point the JWKS configuration at the real JWKS endpoint (…/.well-known/jwks.json / jwks_uri from discovery), never the discovery document itself.
- Validate the JWKS endpoint's JSON shape after any IdP or proxy change.
- Watch for gateways that return HTML/JSON errors with HTTP 200.
When it happens
Trigger: The endpoint at jwksUri returns JSON that is not a JWK Set: an error page (HTML) that still parses as generic JSON, a JSON object without a "keys" array, "keys" being a single object instead of an array, or an array of strings/numbers instead of key objects; in the Kubernetes path, the API server's .well-known/openid-configuration keyset returns an unexpected shape.
Common situations: Misconfigured jwks_uri pointing to the issuer's .well-known/openid-configuration document or a login page instead of the actual JWKS endpoint; a proxy/gateway intercepting the JWKS request and returning an error JSON body; a non-standard IdP or mocked test server serving a hand-written JWKS with a wrong structure.
Understand the failure class
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- ERROR_RETRIEVING_PUBLIC_KEY
- Allowed offset for athenz role token verification must not b
- NO_CLIENT
- ERROR_VERIFYING_JWT
- Authentication has not completed
AI-assisted analysis of apache/pulsar@820761864e (2026-09-06).
Data as JSON: /api/errors/80aebcee16638962.
Report an issue: GitHub.