quarkusio/quarkus · error · org.jose4j.keys.resolvers.UnresolvableKeyException
JWK is not available, neither 'kid' nor 'x5t#S256' nor 'x5t'
Error message
JWK is not available, neither 'kid' nor 'x5t#S256' nor 'x5t' token headers are set
What it means
Thrown by OidcProvider's JsonWebKeyResolver.resolveKey when a token has none of 'kid', 'x5t#S256', or 'x5t' headers and the fallback certificate-chain resolver (chainResolverFallback) also fails to produce a key. There is no header information to select a JWK with, so verification cannot proceed and UnresolvableKeyException is thrown.
Source
Thrown at extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/OidcProvider.java:604
} catch (InvalidAlgorithmException ex) {
LOG.debug("Token 'alg'(algorithm) header value is invalid", ex);
}
}
if (key == null && oidcConfig.jwks().tryAll() && kid == null && thumbprint == null) {
LOG.debug("JWK is not available, neither 'kid' nor 'x5t#S256' nor 'x5t' token headers are set,"
+ " falling back to trying all available keys");
key = jwks.findKeyInAllKeys(jws);
}
if (key == null && chainResolverFallback != null) {
LOG.debug("JWK is not available, neither 'kid' nor 'x5t#S256' nor 'x5t' token headers are set,"
+ " falling back to the certificate chain resolver");
key = chainResolverFallback.resolveKey(jws, nestingContext);
}
if (key == null) {
throw new UnresolvableKeyException(
"JWK is not available, neither 'kid' nor 'x5t#S256' nor 'x5t' token headers are set");
} else {
return key;
}
}
private Key getKeyWithId(String kid) {
if (kid != null) {
return jwks.getKeyWithId(kid);
} else {
LOG.debug("Token 'kid' header is not set");
return null;
}
}
private Key getKeyWithThumbprint(String thumbprint) {
if (thumbprint != null) {
return jwks.getKeyWithThumbprint(thumbprint);View on GitHub (pinned to e1c734241f)
Solutions
- Have the token issuer include a 'kid' header matching a JWKS entry — the standard fix
- Pin the signing key locally with quarkus.oidc.token.public-key so resolution doesn't depend on headers
- Check the token originates from the configured tenant at all
- If the provider publishes exactly one key, ensure JWKS fetching succeeds (network, TLS, jwks-path config)
Example fix
// before: unsigned-header token fails
// after (issuer side):
JWSSigner signer = new RSASSASigner(privateKey);
JWSObject jws = new JWSObject(header.withKeyID("key-1"), payload); // add kid
// or app side: quarkus.oidc.token.public-key=... Defensive patterns
Strategy: validation
Validate before calling
// require a kid header before sending the token for verification
var header = decodeJwtHeader(token);
if (header.get("kid") == null && header.get("x5t#S256") == null && header.get("x5t") == null) {
throw new IllegalStateException("Token has no key-identifying header; cannot verify via JWKS");
} Type guard
boolean hasKeyHint(JsonObject header) {
return header.containsKey("kid") || header.containsKey("x5t#S256") || header.containsKey("x5t");
} Prevention
- Require token issuers to set a 'kid' header
- Configure a local public key to avoid header-dependent resolution
- Verify tokens only from issuers you control the signing configuration of
When it happens
Trigger: Verifying a JWT with a bare JOSE header (no kid/thumbprints) whose signature also cannot be matched by trying all keys via the certificate chain fallback.
Common situations: Token issuer omits 'kid' entirely (common with hand-rolled signers or some JWT libraries) and JWKS contains multiple keys so 'try all' is ambiguous or the cert chain is absent; tokens not actually issued by the configured provider; encrypted-nested tokens where the inner header lacks key hints.
Related errors
- JWK with kid '%s' is not available
- %s type can not be used to represent JWT claims in @Singleto
- DPoP proof token signature is invalid
- Opaque access token can not be converted to JsonWebToken
- ISSUED_AT_INVALID_PAST
AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05).
Data as JSON: /api/errors/452d9e71dfdb9f52.
Report an issue: GitHub.