{"record":{"id":"68d96475858c56e1","repo":"jwtk/jjwt","slug":"compact-jwe-strings-must-always-contain-an-aad-aut","errorCode":null,"errorMessage":"Compact JWE strings must always contain an AAD Authentication Tag.","messagePattern":"Compact JWE strings must always contain an AAD Authentication Tag\\.","errorType":"exception","errorClass":"MalformedJwtException","httpStatus":null,"severity":"error","filePath":"impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtParser.java","lineNumber":537,"sourceCode":"                String msg = \"Compact JWE strings must always contain an Initialization Vector.\";\n                throw new MalformedJwtException(msg);\n            }\n\n            // The AAD (Additional Authenticated Data) scheme for compact JWEs is to use the ASCII bytes of the\n            // raw base64url text as the AAD, and NOT the base64url-decoded bytes per\n            // 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) {","sourceCodeStart":519,"sourceCodeEnd":555,"githubUrl":"https://github.com/jwtk/jjwt/blob/fb71496164c71442d08adec4571d9616ed5e1b8d/impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtParser.java#L519-L555","documentation":"The parser decodes the final JWE segment (the AAD authentication tag used for compact JWEs) and requires it to decode to non-empty bytes. Without a tag the AEAD cipher cannot authenticate the ciphertext, so a missing/empty tag is treated as a MalformedJwtException.","triggerScenarios":"Parsing a compact JWE whose 5th (tag) segment is missing, empty, or decodes to zero bytes via the JWE parse path.","commonSituations":"Truncated tokens (tag cut off by string handling), manual token assembly that omits the tag, confused token types (JWS passed as JWE).","solutions":["Confirm the compact string has 5 segments with a non-empty base64url 5th part.","Regenerate the JWE from the issuer; do not hand-repair the tag.","Check for middleware/logging that may truncate long tokens (URL length limits, header size caps).","Verify you're not accidentally splitting the token on '.' and dropping the last part."],"exampleFix":"// before: parts[0..3] only used, tag dropped\nString truncated = parts[0]+\".\"+parts[1]+\".\"+parts[2]+\".\"+parts[3];\n// after: use the original full token string\nparser.parse(fullJweString);","handlingStrategy":"validation","validationCode":"String[] parts = jwe.split(\"\\\\.\", -1);\nif (parts.length != 5 || parts[4].isEmpty()) throw new IllegalArgumentException(\"JWE missing authentication tag segment\");","typeGuard":null,"tryCatchPattern":"try { parser.parse(jwe); } catch (MalformedJwtException e) { log.warn(\"JWE tag missing/invalid: {}\", e.getMessage()); reject(e); }","preventionTips":["Pass the full original token string; never truncate or rebuild it from parts.","Watch for systems that truncate long tokens (URL limits, log scrubbers, form fields).","End-to-end tests that issue and parse real JWEs catch tag loss early.","Reject tokens at ingress if the segment count is not 5."],"tags":["jwe","authentication-tag","malformed-jwt","aead"],"backgroundTag":"invalid-argument-format","analyzedSha":"fb71496164c71442d08adec4571d9616ed5e1b8d","analyzedAt":"2026-09-09T00:33:09.982Z","contentChangedAt":"2026-09-09T00:33:09.982Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}