JJWT Implementation module providing concrete implementations of JSON Web Token (JWT) creation, parsing, verification, and cryptographic operations for Java and Android applications.
—
The Compression functionality in JJWT Implementation provides payload compression and decompression capabilities for JWT tokens. This includes RFC 1951 DEFLATE compression (standard) and GZIP compression (common extension), helping reduce token size for large payloads while maintaining security and performance.
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.CompressionAlgorithm;
import io.jsonwebtoken.impl.compression.DeflateCompressionAlgorithm;
import io.jsonwebtoken.impl.compression.GzipCompressionAlgorithm;
import io.jsonwebtoken.impl.io.StandardCompressionAlgorithms;
// Access compression algorithm registry
CompressionAlgorithm deflate = Jwts.ZIP.DEF; // DEFLATE (RFC 1951)
CompressionAlgorithm gzip = Jwts.ZIP.GZIP; // GZIP (non-standard but common)
// Get algorithm by ID
CompressionAlgorithm algorithm = Jwts.ZIP.get("DEF");
// List all available algorithms
Collection<CompressionAlgorithm> allAlgorithms = Jwts.ZIP.values();
Set<String> algorithmIds = Jwts.ZIP.get().keySet();import javax.crypto.SecretKey;
// Create compressed JWT with DEFLATE
SecretKey key = Jwts.SIG.HS256.key().build();
String compressedJWT = Jwts.builder()
.subject("user-with-large-claims")
.claim("permissions", Arrays.asList(
"read:users", "write:users", "delete:users",
"read:documents", "write:documents", "delete:documents",
"read:reports", "write:reports", "admin:system"
))
.claim("metadata", Map.of(
"department", "Engineering",
"team", "Backend Development",
"projects", Arrays.asList("project-a", "project-b", "project-c"),
"skills", Arrays.asList("Java", "Python", "JavaScript", "SQL")
))
.compressWith(Jwts.ZIP.DEF)
.signWith(key)
.compact();
// The payload is automatically compressed using DEFLATE// Compressed JWS (signed JWT)
String compressedJWS = Jwts.builder()
.subject("user")
.claim("largeData", generateLargeDataString(10000))
.compressWith(Jwts.ZIP.DEF)
.signWith(signatureKey)
.compact();
// Compressed JWE (encrypted JWT)
SecretKey encryptionKey = Jwts.ENC.A256GCM.key().build();
SecretKey keyEncryptionKey = Jwts.KEY.A256KW.key().build();
String compressedJWE = Jwts.builder()
.subject("confidential-user")
.claim("sensitiveData", largeSensitivePayload)
.claim("documents", listOfLargeDocuments)
.compressWith(Jwts.ZIP.DEF)
.encryptWith(keyEncryptionKey, Jwts.KEY.A256KW, Jwts.ENC.A256GCM)
.compact();
// Compression happens before encryption for security// Direct access to DEFLATE algorithm
DeflateCompressionAlgorithm deflateAlg = new DeflateCompressionAlgorithm();
// Algorithm properties
String algorithmId = deflateAlg.getId(); // "DEF"
// Manual compression/decompression (rarely needed)
String originalData = "Large payload data...";
byte[] compressed = deflateAlg.compress(originalData.getBytes());
byte[] decompressed = deflateAlg.decompress(compressed);
String recovered = new String(decompressed, StandardCharsets.UTF_8);
// recovered equals originalData// Create compressed JWT with GZIP (non-standard but widely supported)
String gzipCompressedJWT = Jwts.builder()
.subject("user")
.claim("bigPayload", massiveDataStructure)
.claim("logs", extensiveLogData)
.compressWith(Jwts.ZIP.GZIP)
.signWith(key)
.compact();
// GZIP typically provides similar compression ratios to DEFLATE
// but includes additional headers// Direct access to GZIP algorithm
GzipCompressionAlgorithm gzipAlg = new GzipCompressionAlgorithm();
// Algorithm properties
String gzipId = gzipAlg.getId(); // "GZIP"
// Manual compression/decompression
byte[] gzipCompressed = gzipAlg.compress(originalData.getBytes());
byte[] gzipDecompressed = gzipAlg.decompress(gzipCompressed);
// GZIP includes checksums and headers for better error detection// Parser automatically handles decompression
JwtParser parser = Jwts.parser()
.verifyWith(key)
.build();
// Parse compressed JWT - decompression is automatic
Jws<Claims> decompressedJws = parser.parseSignedClaims(compressedJWT);
Claims claims = decompressedJws.getPayload();
// Access decompressed claims normally
String subject = claims.getSubject();
List<String> permissions = claims.get("permissions", List.class);
Map<String, Object> metadata = claims.get("metadata", Map.class);// Parse compressed and encrypted JWT
JwtParser encryptedParser = Jwts.parser()
.decryptWith(keyEncryptionKey)
.build();
// Automatic decryption and decompression
Jwe<Claims> decryptedJwe = encryptedParser.parseEncryptedClaims(compressedJWE);
Claims decryptedClaims = decryptedJwe.getPayload();
// Decompression happens after decryption
String sensitiveData = decryptedClaims.get("sensitiveData", String.class);// Choose compression algorithm based on payload characteristics
public static CompressionAlgorithm selectCompressionAlgorithm(Object payload) {
String jsonPayload = serializeToJson(payload);
if (jsonPayload.length() < 1000) {
// Small payloads might not benefit from compression
return null;
}
// For most cases, DEFLATE is preferred (standard compliant)
if (isStandardCompliantRequired()) {
return Jwts.ZIP.DEF;
}
// GZIP for better error detection in unreliable networks
if (requiresErrorDetection()) {
return Jwts.ZIP.GZIP;
}
return Jwts.ZIP.DEF; // Default to DEFLATE
}
// Usage
CompressionAlgorithm algorithm = selectCompressionAlgorithm(largeClaims);
if (algorithm != null) {
String jwt = Jwts.builder()
.claims(largeClaims)
.compressWith(algorithm)
.signWith(key)
.compact();
}// Analyze compression effectiveness
public static CompressionStats analyzeCompression(Object payload) {
String originalJson = serializeToJson(payload);
byte[] originalBytes = originalJson.getBytes(StandardCharsets.UTF_8);
// Test DEFLATE compression
DeflateCompressionAlgorithm deflate = new DeflateCompressionAlgorithm();
byte[] deflateCompressed = deflate.compress(originalBytes);
// Test GZIP compression
GzipCompressionAlgorithm gzip = new GzipCompressionAlgorithm();
byte[] gzipCompressed = gzip.compress(originalBytes);
return new CompressionStats(
originalBytes.length,
deflateCompressed.length,
gzipCompressed.length,
calculateRatio(originalBytes.length, deflateCompressed.length),
calculateRatio(originalBytes.length, gzipCompressed.length)
);
}
public static class CompressionStats {
public final int originalSize;
public final int deflateSize;
public final int gzipSize;
public final double deflateRatio;
public final double gzipRatio;
public CompressionStats(int original, int deflate, int gzip,
double deflateRatio, double gzipRatio) {
this.originalSize = original;
this.deflateSize = deflate;
this.gzipSize = gzip;
this.deflateRatio = deflateRatio;
this.gzipRatio = gzipRatio;
}
}
private static double calculateRatio(int original, int compressed) {
return (double) (original - compressed) / original * 100.0;
}// WARNING: Compression with unsecured JWTs can be a security risk
// Always use signature or encryption with compression
// Secure: Compression with signature
String secureCompressed = Jwts.builder()
.subject("user")
.claim("data", largeData)
.compressWith(Jwts.ZIP.DEF)
.signWith(secretKey) // Always sign compressed content
.compact();
// More secure: Compression with encryption
String encryptedCompressed = Jwts.builder()
.subject("user")
.claim("sensitiveData", largeSensitiveData)
.compressWith(Jwts.ZIP.DEF)
.encryptWith(kekKey, Jwts.KEY.A256KW, Jwts.ENC.A256GCM)
.compact();// Control decompression of unsecured JWTs (use with extreme caution)
JwtParser unsecuredParser = Jwts.parser()
.unsecured() // Allow unsecured JWTs
.unsecuredDecompression() // Allow decompression of unsecured JWTs
.build();
// This should only be used in very specific, controlled environments
// Prefer signed or encrypted compressed JWTs// Only compress if payload exceeds threshold
public static String createOptimalJWT(Claims claims, SecretKey key) {
String claimsJson = serializeToJson(claims);
JwtBuilder builder = Jwts.builder()
.claims(claims)
.signWith(key);
// Only compress if payload is large enough to benefit
if (claimsJson.length() > 500) { // 500 byte threshold
builder.compressWith(Jwts.ZIP.DEF);
}
return builder.compact();
}// For very large payloads, consider streaming
public static String createStreamCompressedJWT(InputStream largePayload,
SecretKey key) {
return Jwts.builder()
.content(largePayload) // Stream directly
.compressWith(Jwts.ZIP.DEF)
.signWith(key)
.compact();
}
// Parser handles streaming decompression automatically
public static String parseStreamCompressedJWT(String jwt, SecretKey key) {
JwtParser parser = Jwts.parser()
.verifyWith(key)
.build();
Jws<String> jws = parser.parseSignedContent(jwt);
return jws.getPayload(); // Automatically decompressed
}// Custom compression algorithm implementation
public class CustomCompressionAlgorithm implements CompressionAlgorithm {
@Override
public String getId() {
return "CUSTOM";
}
@Override
public byte[] compress(byte[] payload) throws CompressionException {
// Custom compression implementation
return compressWithCustomAlgorithm(payload);
}
@Override
public byte[] decompress(byte[] compressed) throws CompressionException {
// Custom decompression implementation
return decompressWithCustomAlgorithm(compressed);
}
}
// Register custom algorithm
CompressionAlgorithm customAlg = new CustomCompressionAlgorithm();
// Use with parser
JwtParser customParser = Jwts.parser()
.verifyWith(key)
.zip() // Access compression registry
.add(customAlg)
.and()
.build();
// Use with builder
String customCompressedJWT = Jwts.builder()
.subject("user")
.claim("data", data)
.compressWith(customAlg)
.signWith(key)
.compact();import io.jsonwebtoken.CompressionException;
try {
String compressedJWT = Jwts.builder()
.subject("user")
.claim("corruptData", potentiallyCorruptData)
.compressWith(Jwts.ZIP.DEF)
.signWith(key)
.compact();
} catch (CompressionException e) {
// Handle compression failure
log.error("Compression failed", e);
// Fallback to uncompressed JWT
String fallbackJWT = Jwts.builder()
.subject("user")
.claim("data", alternativeData)
.signWith(key)
.compact();
}try {
Jws<Claims> jws = parser.parseSignedClaims(compressedJWT);
Claims claims = jws.getPayload();
} catch (CompressionException e) {
// Handle decompression failure
log.error("Decompression failed", e);
throw new SecurityException("Invalid compressed token", e);
} catch (Exception e) {
// Handle other parsing errors
log.error("Token parsing failed", e);
throw new IllegalArgumentException("Invalid token", e);
}// Ideal candidates for compression:
// 1. Large claim sets
Map<String, Object> largeClaims = Map.of(
"permissions", Arrays.asList(/* many permissions */),
"userProfile", Map.of(/* detailed profile */),
"sessionData", Map.of(/* extensive session info */),
"preferences", Map.of(/* many user preferences */)
);
// 2. Repeated/structured data
List<Map<String, Object>> structuredData = Arrays.asList(
Map.of("id", 1, "name", "Item 1", "description", "Long description..."),
Map.of("id", 2, "name", "Item 2", "description", "Another long description..."),
// ... many similar items
);
// 3. JSON with repetitive keys
Map<String, Object> repetitiveData = Map.of(
"configuration", Map.of(
"feature_flag_1", true,
"feature_flag_2", false,
"feature_flag_3", true
// ... many feature flags
)
);
// Compression decision logic
public static boolean shouldCompress(Object payload) {
String json = serializeToJson(payload);
// Don't compress small payloads
if (json.length() < 200) return false;
// Always compress very large payloads
if (json.length() > 2000) return true;
// Analyze repetition for medium payloads
return hasHighRepetition(json);
}// Pre-compress reusable content
public class JWTCompressionCache {
private final Map<String, byte[]> compressionCache = new ConcurrentHashMap<>();
public String createCachedCompressedJWT(String cacheKey, Object payload, SecretKey key) {
byte[] compressed = compressionCache.computeIfAbsent(cacheKey, k -> {
String json = serializeToJson(payload);
return Jwts.ZIP.DEF.compress(json.getBytes(StandardCharsets.UTF_8));
});
// Use pre-compressed content
return Jwts.builder()
.content(compressed)
.header()
.add("zip", "DEF") // Indicate compression
.and()
.signWith(key)
.compact();
}
}The Compression functionality provides efficient payload reduction for JWTs while maintaining security and RFC compliance, with automatic handling in both creation and parsing scenarios.
Install with Tessl CLI
npx tessl i tessl/maven-io-jsonwebtoken--jjwt-impl