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

  1. Have the token issuer include a 'kid' header matching a JWKS entry — the standard fix
  2. Pin the signing key locally with quarkus.oidc.token.public-key so resolution doesn't depend on headers
  3. Check the token originates from the configured tenant at all
  4. 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

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


AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05). Data as JSON: /api/errors/452d9e71dfdb9f52. Report an issue: GitHub.