{"record":{"id":"ae258fa576adf296","repo":"jwtk/jjwt","slug":"cannot-decrypt-jwe-payload-unable-to-locate-key-f","errorCode":null,"errorMessage":"Cannot decrypt JWE payload: unable to locate key for JWE with header: + jweHeader","messagePattern":"Cannot decrypt JWE payload: unable to locate key for JWE with header: \\+ jweHeader","errorType":"exception","errorClass":"UnsupportedJwtException","httpStatus":null,"severity":"error","filePath":"impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtParser.java","lineNumber":543,"sourceCode":"            // https://www.rfc-editor.org/rfc/rfc7516.html#section-5.1, Step 14.\n            ByteBuffer buf = StandardCharsets.US_ASCII.encode(Strings.wrap(base64UrlHeader));\n            final byte[] aadBytes = new byte[buf.remaining()];\n            buf.get(aadBytes);\n            InputStream aad = Streams.of(aadBytes);\n\n            base64Url = base64UrlDigest;\n            //guaranteed to be non-empty via the `alg` + digest check above:\n            Assert.hasText(base64Url, \"JWE AAD Authentication Tag cannot be null or empty.\");\n            digest = decode(base64Url, \"JWE AAD Authentication Tag\");\n            if (Bytes.isEmpty(digest)) {\n                String msg = \"Compact JWE strings must always contain an AAD Authentication Tag.\";\n                throw new MalformedJwtException(msg);\n            }\n\n            Key key = this.keyLocator.locate(jweHeader);\n            if (key == null) {\n                String msg = \"Cannot decrypt JWE payload: unable to locate key for JWE with header: \" + jweHeader;\n                throw new UnsupportedJwtException(msg);\n            }\n            if (key instanceof PublicKey) {\n                throw new InvalidKeyException(PUB_KEY_DECRYPT_MSG);\n            }\n\n            // extract key-specific provider if necessary;\n            Provider provider = ProviderKey.getProvider(key, this.provider);\n            key = ProviderKey.getKey(key); // this must be called after ProviderKey.getProvider\n            DecryptionKeyRequest<Key> request =\n                    new DefaultDecryptionKeyRequest<>(cekBytes, provider, null, jweHeader, encAlg, key);\n            final SecretKey cek = keyAlg.getDecryptionKey(request);\n            if (cek == null) {\n                String msg = \"The '\" + keyAlg.getId() + \"' JWE key algorithm did not return a decryption key. \" +\n                        \"Unable to perform '\" + encAlg.getId() + \"' decryption.\";\n                throw new IllegalStateException(msg);\n            }\n\n            // During decryption, the available Provider applies to the KeyAlgorithm, not the AeadAlgorithm, mostly","sourceCodeStart":525,"sourceCodeEnd":561,"githubUrl":"https://github.com/jwtk/jjwt/blob/fb71496164c71442d08adec4571d9616ed5e1b8d/impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtParser.java#L525-L561","documentation":"Before decrypting a JWE the parser calls the configured keyLocator to obtain the decryption key for the token's header; if the locator returns null, decryption is impossible and the parser throws UnsupportedJwtException naming the header so you can see which key the token expected.","triggerScenarios":"Parsing a JWE when no KeyLocator/Locator is configured, or the configured locator returns null for the token's alg/kid header (e.g. kid not present in the key store).","commonSituations":"Forgetting to call .keyLocator(...) or .decryptWith(key) on JwtParserBuilder, key rotation removing the kid the token references, multi-tenant lookup returning null for unknown issuers.","solutions":["Configure a key source: call decryptWith(SecretKey/PrivateKey) or keyLocator(Locator) on the JwtParserBuilder before parsing.","Ensure the locator handles the token's kid/alg and returns a matching key, or throw with a clear message instead of returning null.","Verify key rotation: if the kid is unknown, load archived keys or reject the token upstream.","Log the JWE header (alg, kid, enc) and confirm your key store contains the corresponding key."],"exampleFix":"// before\nJwtParser parser = Jwts.parser().build();\n// after\nJwtParser parser = Jwts.parser()\n    .keyLocator(header -> keyStore.get(header.get(\"kid\", String.class)))\n    .build();","handlingStrategy":"try-catch","validationCode":"// ensure a key source is wired before parsing\nObjects.requireNonNull(myDecryptionKeyOrLocator, \"JWE decryption key/locator must be configured\");","typeGuard":null,"tryCatchPattern":"try { parser.parse(jwe); } catch (UnsupportedJwtException e) { if (e.getMessage().startsWith(\"Cannot decrypt JWE payload\")) { /* load/refresh key for kid, then retry */ } }","preventionTips":["Always configure decryptWith(...) or keyLocator(...) before parsing JWEs.","Make key locators key-rotation aware (support archived kids) and throw instead of returning null on miss.","Log the JWE header (kid/alg) when key lookup fails for faster diagnosis.","Unit-test the locator against every kid your issuers can produce."],"tags":["jwe","key-locator","decryption","missing-key"],"backgroundTag":"missing-credentials","analyzedSha":"fb71496164c71442d08adec4571d9616ed5e1b8d","analyzedAt":"2026-09-09T00:33:09.982Z","contentChangedAt":"2026-09-09T00:33:09.982Z","schemaVersion":2},"datasetVersion":"2026-09-17T15:17:12.973Z"}