{"record":{"id":"a06d640d8088074b","repo":"quarkusio/quarkus","slug":"jwk-with-kid-s-is-not-available","errorCode":null,"errorMessage":"JWK with kid '%s' is not available","messagePattern":"JWK with kid '(.+?)' is not available","errorType":"exception","errorClass":"org.jose4j.keys.resolvers.UnresolvableKeyException","httpStatus":401,"severity":"error","filePath":"extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/OidcProvider.java","lineNumber":554,"sourceCode":"            if (oidcConfig.certificateChain().trustStoreFile().isPresent()) {\n                chainResolverFallback = new CertChainPublicKeyResolver(oidcConfig);\n            } else {\n                chainResolverFallback = null;\n            }\n        }\n\n        @Override\n        public Key resolveKey(JsonWebSignature jws, List<JsonWebStructure> nestingContext)\n                throws UnresolvableKeyException {\n            Key key = null;\n\n            // Try 'kid' first\n            String kid = jws.getKeyIdHeaderValue();\n            if (kid != null) {\n                key = getKeyWithId(kid);\n                if (key == null) {\n                    // if `kid` was set then the key must exist\n                    throw new UnresolvableKeyException(String.format(\"JWK with kid '%s' is not available\", kid));\n                }\n            }\n\n            String thumbprint = null;\n            if (key == null) {\n                thumbprint = jws.getHeader(HeaderParameterNames.X509_CERTIFICATE_SHA256_THUMBPRINT);\n                if (thumbprint != null) {\n                    key = getKeyWithS256Thumbprint(thumbprint);\n                    if (key == null) {\n                        // if only `x5tS256` was set then the key must exist\n                        throw new UnresolvableKeyException(\n                                String.format(\"JWK with the SHA256 certificate thumbprint '%s' is not available\", thumbprint));\n                    }\n                }\n            }\n\n            if (key == null) {\n                thumbprint = jws.getHeader(HeaderParameterNames.X509_CERTIFICATE_THUMBPRINT);","sourceCodeStart":536,"sourceCodeEnd":572,"githubUrl":"https://github.com/quarkusio/quarkus/blob/e1c734241f34c7919086ceb4c9262b4a58f6de44/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/OidcProvider.java#L536-L572","documentation":"Thrown by OidcProvider's JsonWebKeyResolver.resolveKey when a signed JWT carries a 'kid' (key ID) header but no matching JWK can be found in the tenant's JSON Web Key Set. Per RFC 7515 semantics, once the token declares a 'kid' the verifier must use exactly that key; the provider refuses to fall back to other keys or thumbprint matching. This is a fail-fast safeguard against tokens signed with unknown or rotated-out keys.","triggerScenarios":"Verifying an ID token/access token whose JOSE header contains 'kid' while getKeyWithId(kid) returns null — i.e. the JWKS fetched from the OIDC provider (or the local quarkus.oidc.* jwks/key config) has no key with that 'kid'.","commonSituations":"The OIDC provider rotated signing keys but the app still holds a cached/stale JWKS; a typo'd or misconfigured jwks.path / jwks.resolve-early setting; testing tokens issued by a different realm/tenant than the one configured; custom or third-party identity providers whose 'kid' values don't match what's published in the JWKS endpoint.","solutions":["Force a JWKS refresh (restart the app or invalidate the cached key set) so keys rotated at the provider are re-fetched","Verify the token was issued by the tenant/realm you configured — check quarkus.oidc.auth-server-url / jwks-path matches the token issuer","Compare the token's 'kid' header (decode the JWT at jwt.io or similar) against the keys published at the JWKS endpoint","If the provider doesn't publish 'kid' but the token has one, remove the mismatch or configure the signing key locally via quarkus.oidc.token.public-key / certificate"],"exampleFix":"// token kid 'key-2' but only 'key-1' published after rotation\n// before: stale cached JWKS -> UnresolvableKeyException\n// after: make refresh interval aggressive and align tenant config\nquarkus.oidc.token.audience=...","handlingStrategy":"fallback","validationCode":"// decode token header and check kid is present in fetched JWKS before verification\nString kid = com.nimbusds.jose.JOSEHeader parse of token; // or decode base64url header JSON\nSet<String> availableKids = fetchedJwks.getKeys().stream().map(JsonWebKey::getKeyId).collect(Collectors.toSet());\nif (!availableKids.contains(kid)) { throw new IllegalStateException(\"kid \" + kid + \" missing from JWKS\"); }","typeGuard":"boolean jwksHasKid(String jwksJson, String kid) {\n    var set = io.quarkus.oidc.runtime.OidcUtils.parse JWKS if available;\n    return set != null && set.getKeys().stream().anyMatch(k -> kid.equals(k.getKeyId()));\n}","tryCatchPattern":"try {\n    SecurityIdentity id = identityProvider.authenticate(...);\n} catch (AuthenticationFailedException e) {\n    if (e.getCause() instanceof UnresolvableKeyException) {\n        // request JWKS refresh / retry verification once\n    }\n}","preventionTips":["Set a short JWKS refresh interval so provider key rotation is picked up quickly","Monitor the token's kid header against the JWKS endpoint in CI against your providers","Pin signing keys locally for trusted providers to avoid runtime resolution","Keep tenant auth-server-url/jwks-path in sync with the actual token issuer"],"tags":["jwt","oidc","jwks","key-resolution"],"backgroundTag":"jwk-kid-not-found","analyzedSha":"e1c734241f34c7919086ceb4c9262b4a58f6de44","analyzedAt":"2026-09-05T17:01:29.979Z","contentChangedAt":"2026-09-05T17:01:29.979Z","schemaVersion":2},"datasetVersion":"2026-09-12T22:17:10.623Z"}