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
- 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.
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
- 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.
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.
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
- Compact JWE strings must always contain an Initialization Ve
- Ciphertext decryption failed: Authentication tag verificatio
- Compact JWE string represents an encrypted key, but the key
- Unexpected content JWE.
- Unexpected Claims JWE.
AI-assisted analysis of jwtk/jjwt@fb71496164 (2026-09-09).
Data as JSON: /api/errors/68d96475858c56e1.
Report an issue: GitHub.