jwtk/jjwt · error · MalformedJwtException

Compact JWE strings must always contain an AAD Authenticatio

Error message

Compact JWE strings must always contain an AAD Authentication Tag.

What it means

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.

Source

Thrown at impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtParser.java:537

                String msg = "Compact JWE strings must always contain an Initialization Vector.";
                throw new MalformedJwtException(msg);
            }

            // The AAD (Additional Authenticated Data) scheme for compact JWEs is to use the ASCII bytes of the
            // raw base64url text as the AAD, and NOT the base64url-decoded bytes per
            // https://www.rfc-editor.org/rfc/rfc7516.html#section-5.1, Step 14.
            ByteBuffer buf = StandardCharsets.US_ASCII.encode(Strings.wrap(base64UrlHeader));
            final byte[] aadBytes = new byte[buf.remaining()];
            buf.get(aadBytes);
            InputStream aad = Streams.of(aadBytes);

            base64Url = base64UrlDigest;
            //guaranteed to be non-empty via the `alg` + digest check above:
            Assert.hasText(base64Url, "JWE AAD Authentication Tag cannot be null or empty.");
            digest = decode(base64Url, "JWE AAD Authentication Tag");
            if (Bytes.isEmpty(digest)) {
                String msg = "Compact JWE strings must always contain an AAD Authentication Tag.";
                throw new MalformedJwtException(msg);
            }

            Key key = this.keyLocator.locate(jweHeader);
            if (key == null) {
                String msg = "Cannot decrypt JWE payload: unable to locate key for JWE with header: " + jweHeader;
                throw new UnsupportedJwtException(msg);
            }
            if (key instanceof PublicKey) {
                throw new InvalidKeyException(PUB_KEY_DECRYPT_MSG);
            }

            // extract key-specific provider if necessary;
            Provider provider = ProviderKey.getProvider(key, this.provider);
            key = ProviderKey.getKey(key); // this must be called after ProviderKey.getProvider
            DecryptionKeyRequest<Key> request =
                    new DefaultDecryptionKeyRequest<>(cekBytes, provider, null, jweHeader, encAlg, key);
            final SecretKey cek = keyAlg.getDecryptionKey(request);
            if (cek == null) {

View on GitHub (pinned to fb71496164)

Solutions

  1. Confirm the compact string has 5 segments with a non-empty base64url 5th part.
  2. Regenerate the JWE from the issuer; do not hand-repair the tag.
  3. Check for middleware/logging that may truncate long tokens (URL length limits, header size caps).
  4. Verify you're not accidentally splitting the token on '.' and dropping the last part.

Example fix

// before: parts[0..3] only used, tag dropped
String truncated = parts[0]+"."+parts[1]+"."+parts[2]+"."+parts[3];
// after: use the original full token string
parser.parse(fullJweString);
Defensive patterns

Strategy: validation

Validate before calling

String[] parts = jwe.split("\\.", -1);
if (parts.length != 5 || parts[4].isEmpty()) throw new IllegalArgumentException("JWE missing authentication tag segment");

Try / catch

try { parser.parse(jwe); } catch (MalformedJwtException e) { log.warn("JWE tag missing/invalid: {}", e.getMessage()); reject(e); }

Prevention

When it happens

Trigger: Parsing a compact JWE whose 5th (tag) segment is missing, empty, or decodes to zero bytes via the JWE parse path.

Common situations: Truncated tokens (tag cut off by string handling), manual token assembly that omits the tag, confused token types (JWS passed as JWE).

Understand the failure class

Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.

Related errors


AI-assisted analysis of jwtk/jjwt@fb71496164 (2026-09-09). Data as JSON: /api/errors/68d96475858c56e1. Report an issue: GitHub.