jwtk/jjwt · error · UnsupportedJwtException
The JWT header references compression algorithm '%s', but pa
Error message
The JWT header references compression algorithm '%s', but payload decompression for Unencoded JWSs (those with a b64 header value of false) that rely on a SigningKeyResolver are disallowed by default to protect against [Denial of Service attacks](https://www.usenix.org/system/files/conference/usenixsecurity15/sec15-paper-pellegrino.pdf). If you wish to enable Unencoded JWS payload decompression, configure the JwtParserBuilder.keyLocator(Locator) and do not configure a SigningKeyResolver.
What it means
For unencoded JWSs (b64=false) whose payload compression is requested, the library refuses to decompress when integrity wasn't cryptographically verified and a SigningKeyResolver is in use, because decompressing attacker-controlled data enables DoS (zip bombs). It throws UnsupportedJwtException instructing you to switch to a KeyLocator.
Source
Thrown at impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtParser.java:586
encAlg.decrypt(dreq, plaintext);
payload = new Payload(plaintext.toByteArray(), header.getContentType());
integrityVerified = true; // AEAD performs integrity verification, so no exception = verified
} else if (hasDigest && this.signingKeyResolver == null) { //TODO: for 1.0, remove the == null check
// not using a signing key resolver, so we can verify the signature before reading the payload, which is
// always safer:
JwsHeader jwsHeader = Assert.stateIsInstance(JwsHeader.class, header, "Not a JwsHeader. ");
digest = verifySignature(tokenized, jwsHeader, alg, new LocatingKeyResolver(this.keyLocator), null, payload);
integrityVerified = true; // no exception means signature verified
}
final CompressionAlgorithm compressionAlgorithm = zipAlgs.apply(header);
if (compressionAlgorithm != null) {
if (!integrityVerified) {
if (!payloadBase64UrlEncoded) {
String msg = String.format(B64_DECOMPRESSION_MSG, compressionAlgorithm.getId());
throw new UnsupportedJwtException(msg);
} else if (!unsecuredDecompression) {
String msg = String.format(UNPROTECTED_DECOMPRESSION_MSG, compressionAlgorithm.getId());
throw new UnsupportedJwtException(msg);
}
}
payload = payload.decompress(compressionAlgorithm);
}
Claims claims = null;
byte[] payloadBytes = payload.getBytes();
if (payload.isConsumable()) {
InputStream in = null;
try {
in = payload.toInputStream();
if (!hasContentType(header)) { // If there is a content type set, then the application using JJWT is expected
// to convert the byte payload themselves based on this content type
// https://www.rfc-editor.org/rfc/rfc7515.html#section-4.1.10 :View on GitHub (pinned to fb71496164)
Solutions
- Replace SigningKeyResolver with JwtParserBuilder.keyLocator(Locator) so integrity is verified before decompression.
- Remove compression (zip header) from unencoded JWSs, or use standard encoded JWSs where decompression after verification is safe.
- If you must keep the old flow and accept the risk, call .unsecuredDecompression() on the builder after reading its security JavaDoc.
- Verify the token producer really needs b64:false; most use cases should not use unencoded payloads.
Example fix
// before Jwts.parser().setSigningKeyResolver(resolver).build().parse(jws); // after Jwts.parser().keyLocator(header -> key).build().parse(jws);
Defensive patterns
Strategy: try-catch
Validate before calling
Map<String,Object> h = getUntrustedHeader(token); // decode header without parsing payload
boolean unsafe = h.containsKey("zip") && h.containsKey("b64") && Boolean.FALSE.equals(h.get("b64")) && usingSigningKeyResolver; Try / catch
try { parser.parse(jws); } catch (UnsupportedJwtException e) { if (e.getMessage().contains("decompression")) { /* migrate to keyLocator or enable explicitly */ } } Prevention
- Prefer keyLocator(Locator) over the deprecated SigningKeyResolver APIs.
- Avoid compressing unencoded payloads; use standard encoded JWSs.
- Only enable unsecuredDecompression() after reading its security JavaDoc.
- Strip zip headers at the producer unless verified-token decompression is intended.
When it happens
Trigger: Parsing an unencoded JWS (b64:false header) with a zip/def header while a SigningKeyResolver is configured and unsecuredDecompression() was not called.
Common situations: Legacy code using deprecated setSigningKeyResolver APIs combined with compressed unencoded payloads, migration from older JJWT versions where this was allowed, tokens produced with custom unencoded+compressed formats.
Related errors
- The JWT header references compression algorithm '%s', but pa
- 'unsecuredDecompression' is only relevant if 'unsecured' is
- Both 'zip()' and 'compressionCodecResolver' cannot be config
- Malformed or excessively complex ${name} JSON. If experience
- JWE Header ${param} value ${iterations} exceeds ${getId()} m
AI-assisted analysis of jwtk/jjwt@fb71496164 (2026-09-09).
Data as JSON: /api/errors/f4eb9d7807dfd0cc.
Report an issue: GitHub.