0
# Compression
1
2
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.
3
4
## Core Compression Classes
5
6
### Compression Algorithm Registry
7
8
```java { .api }
9
import io.jsonwebtoken.Jwts;
10
import io.jsonwebtoken.CompressionAlgorithm;
11
import io.jsonwebtoken.impl.compression.DeflateCompressionAlgorithm;
12
import io.jsonwebtoken.impl.compression.GzipCompressionAlgorithm;
13
import io.jsonwebtoken.impl.io.StandardCompressionAlgorithms;
14
15
// Access compression algorithm registry
16
CompressionAlgorithm deflate = Jwts.ZIP.DEF; // DEFLATE (RFC 1951)
17
CompressionAlgorithm gzip = Jwts.ZIP.GZIP; // GZIP (non-standard but common)
18
19
// Get algorithm by ID
20
CompressionAlgorithm algorithm = Jwts.ZIP.get("DEF");
21
22
// List all available algorithms
23
Collection<CompressionAlgorithm> allAlgorithms = Jwts.ZIP.values();
24
Set<String> algorithmIds = Jwts.ZIP.get().keySet();
25
```
26
27
## DEFLATE Compression
28
29
### Basic DEFLATE Usage
30
31
```java { .api }
32
import javax.crypto.SecretKey;
33
34
// Create compressed JWT with DEFLATE
35
SecretKey key = Jwts.SIG.HS256.key().build();
36
37
String compressedJWT = Jwts.builder()
38
.subject("user-with-large-claims")
39
.claim("permissions", Arrays.asList(
40
"read:users", "write:users", "delete:users",
41
"read:documents", "write:documents", "delete:documents",
42
"read:reports", "write:reports", "admin:system"
43
))
44
.claim("metadata", Map.of(
45
"department", "Engineering",
46
"team", "Backend Development",
47
"projects", Arrays.asList("project-a", "project-b", "project-c"),
48
"skills", Arrays.asList("Java", "Python", "JavaScript", "SQL")
49
))
50
.compressWith(Jwts.ZIP.DEF)
51
.signWith(key)
52
.compact();
53
54
// The payload is automatically compressed using DEFLATE
55
```
56
57
### DEFLATE with Different JWT Types
58
59
```java { .api }
60
// Compressed JWS (signed JWT)
61
String compressedJWS = Jwts.builder()
62
.subject("user")
63
.claim("largeData", generateLargeDataString(10000))
64
.compressWith(Jwts.ZIP.DEF)
65
.signWith(signatureKey)
66
.compact();
67
68
// Compressed JWE (encrypted JWT)
69
SecretKey encryptionKey = Jwts.ENC.A256GCM.key().build();
70
SecretKey keyEncryptionKey = Jwts.KEY.A256KW.key().build();
71
72
String compressedJWE = Jwts.builder()
73
.subject("confidential-user")
74
.claim("sensitiveData", largeSensitivePayload)
75
.claim("documents", listOfLargeDocuments)
76
.compressWith(Jwts.ZIP.DEF)
77
.encryptWith(keyEncryptionKey, Jwts.KEY.A256KW, Jwts.ENC.A256GCM)
78
.compact();
79
80
// Compression happens before encryption for security
81
```
82
83
### DEFLATE Algorithm Details
84
85
```java { .api }
86
// Direct access to DEFLATE algorithm
87
DeflateCompressionAlgorithm deflateAlg = new DeflateCompressionAlgorithm();
88
89
// Algorithm properties
90
String algorithmId = deflateAlg.getId(); // "DEF"
91
92
// Manual compression/decompression (rarely needed)
93
String originalData = "Large payload data...";
94
byte[] compressed = deflateAlg.compress(originalData.getBytes());
95
byte[] decompressed = deflateAlg.decompress(compressed);
96
97
String recovered = new String(decompressed, StandardCharsets.UTF_8);
98
// recovered equals originalData
99
```
100
101
## GZIP Compression
102
103
### Basic GZIP Usage
104
105
```java { .api }
106
// Create compressed JWT with GZIP (non-standard but widely supported)
107
String gzipCompressedJWT = Jwts.builder()
108
.subject("user")
109
.claim("bigPayload", massiveDataStructure)
110
.claim("logs", extensiveLogData)
111
.compressWith(Jwts.ZIP.GZIP)
112
.signWith(key)
113
.compact();
114
115
// GZIP typically provides similar compression ratios to DEFLATE
116
// but includes additional headers
117
```
118
119
### GZIP Algorithm Details
120
121
```java { .api }
122
// Direct access to GZIP algorithm
123
GzipCompressionAlgorithm gzipAlg = new GzipCompressionAlgorithm();
124
125
// Algorithm properties
126
String gzipId = gzipAlg.getId(); // "GZIP"
127
128
// Manual compression/decompression
129
byte[] gzipCompressed = gzipAlg.compress(originalData.getBytes());
130
byte[] gzipDecompressed = gzipAlg.decompress(gzipCompressed);
131
132
// GZIP includes checksums and headers for better error detection
133
```
134
135
## Compression with Parsing
136
137
### Parsing Compressed JWTs
138
139
```java { .api }
140
// Parser automatically handles decompression
141
JwtParser parser = Jwts.parser()
142
.verifyWith(key)
143
.build();
144
145
// Parse compressed JWT - decompression is automatic
146
Jws<Claims> decompressedJws = parser.parseSignedClaims(compressedJWT);
147
Claims claims = decompressedJws.getPayload();
148
149
// Access decompressed claims normally
150
String subject = claims.getSubject();
151
List<String> permissions = claims.get("permissions", List.class);
152
Map<String, Object> metadata = claims.get("metadata", Map.class);
153
```
154
155
### Compressed JWE Parsing
156
157
```java { .api }
158
// Parse compressed and encrypted JWT
159
JwtParser encryptedParser = Jwts.parser()
160
.decryptWith(keyEncryptionKey)
161
.build();
162
163
// Automatic decryption and decompression
164
Jwe<Claims> decryptedJwe = encryptedParser.parseEncryptedClaims(compressedJWE);
165
Claims decryptedClaims = decryptedJwe.getPayload();
166
167
// Decompression happens after decryption
168
String sensitiveData = decryptedClaims.get("sensitiveData", String.class);
169
```
170
171
## Advanced Compression Features
172
173
### Compression Algorithm Selection
174
175
```java { .api }
176
// Choose compression algorithm based on payload characteristics
177
public static CompressionAlgorithm selectCompressionAlgorithm(Object payload) {
178
String jsonPayload = serializeToJson(payload);
179
180
if (jsonPayload.length() < 1000) {
181
// Small payloads might not benefit from compression
182
return null;
183
}
184
185
// For most cases, DEFLATE is preferred (standard compliant)
186
if (isStandardCompliantRequired()) {
187
return Jwts.ZIP.DEF;
188
}
189
190
// GZIP for better error detection in unreliable networks
191
if (requiresErrorDetection()) {
192
return Jwts.ZIP.GZIP;
193
}
194
195
return Jwts.ZIP.DEF; // Default to DEFLATE
196
}
197
198
// Usage
199
CompressionAlgorithm algorithm = selectCompressionAlgorithm(largeClaims);
200
if (algorithm != null) {
201
String jwt = Jwts.builder()
202
.claims(largeClaims)
203
.compressWith(algorithm)
204
.signWith(key)
205
.compact();
206
}
207
```
208
209
### Compression Ratio Analysis
210
211
```java { .api }
212
// Analyze compression effectiveness
213
public static CompressionStats analyzeCompression(Object payload) {
214
String originalJson = serializeToJson(payload);
215
byte[] originalBytes = originalJson.getBytes(StandardCharsets.UTF_8);
216
217
// Test DEFLATE compression
218
DeflateCompressionAlgorithm deflate = new DeflateCompressionAlgorithm();
219
byte[] deflateCompressed = deflate.compress(originalBytes);
220
221
// Test GZIP compression
222
GzipCompressionAlgorithm gzip = new GzipCompressionAlgorithm();
223
byte[] gzipCompressed = gzip.compress(originalBytes);
224
225
return new CompressionStats(
226
originalBytes.length,
227
deflateCompressed.length,
228
gzipCompressed.length,
229
calculateRatio(originalBytes.length, deflateCompressed.length),
230
calculateRatio(originalBytes.length, gzipCompressed.length)
231
);
232
}
233
234
public static class CompressionStats {
235
public final int originalSize;
236
public final int deflateSize;
237
public final int gzipSize;
238
public final double deflateRatio;
239
public final double gzipRatio;
240
241
public CompressionStats(int original, int deflate, int gzip,
242
double deflateRatio, double gzipRatio) {
243
this.originalSize = original;
244
this.deflateSize = deflate;
245
this.gzipSize = gzip;
246
this.deflateRatio = deflateRatio;
247
this.gzipRatio = gzipRatio;
248
}
249
}
250
251
private static double calculateRatio(int original, int compressed) {
252
return (double) (original - compressed) / original * 100.0;
253
}
254
```
255
256
## Security Considerations
257
258
### Compression with Unsecured JWTs
259
260
```java { .api }
261
// WARNING: Compression with unsecured JWTs can be a security risk
262
// Always use signature or encryption with compression
263
264
// Secure: Compression with signature
265
String secureCompressed = Jwts.builder()
266
.subject("user")
267
.claim("data", largeData)
268
.compressWith(Jwts.ZIP.DEF)
269
.signWith(secretKey) // Always sign compressed content
270
.compact();
271
272
// More secure: Compression with encryption
273
String encryptedCompressed = Jwts.builder()
274
.subject("user")
275
.claim("sensitiveData", largeSensitiveData)
276
.compressWith(Jwts.ZIP.DEF)
277
.encryptWith(kekKey, Jwts.KEY.A256KW, Jwts.ENC.A256GCM)
278
.compact();
279
```
280
281
### Unsecured Decompression Control
282
283
```java { .api }
284
// Control decompression of unsecured JWTs (use with extreme caution)
285
JwtParser unsecuredParser = Jwts.parser()
286
.unsecured() // Allow unsecured JWTs
287
.unsecuredDecompression() // Allow decompression of unsecured JWTs
288
.build();
289
290
// This should only be used in very specific, controlled environments
291
// Prefer signed or encrypted compressed JWTs
292
```
293
294
## Performance Optimization
295
296
### Compression Threshold
297
298
```java { .api }
299
// Only compress if payload exceeds threshold
300
public static String createOptimalJWT(Claims claims, SecretKey key) {
301
String claimsJson = serializeToJson(claims);
302
303
JwtBuilder builder = Jwts.builder()
304
.claims(claims)
305
.signWith(key);
306
307
// Only compress if payload is large enough to benefit
308
if (claimsJson.length() > 500) { // 500 byte threshold
309
builder.compressWith(Jwts.ZIP.DEF);
310
}
311
312
return builder.compact();
313
}
314
```
315
316
### Streaming Compression
317
318
```java { .api }
319
// For very large payloads, consider streaming
320
public static String createStreamCompressedJWT(InputStream largePayload,
321
SecretKey key) {
322
return Jwts.builder()
323
.content(largePayload) // Stream directly
324
.compressWith(Jwts.ZIP.DEF)
325
.signWith(key)
326
.compact();
327
}
328
329
// Parser handles streaming decompression automatically
330
public static String parseStreamCompressedJWT(String jwt, SecretKey key) {
331
JwtParser parser = Jwts.parser()
332
.verifyWith(key)
333
.build();
334
335
Jws<String> jws = parser.parseSignedContent(jwt);
336
return jws.getPayload(); // Automatically decompressed
337
}
338
```
339
340
## Custom Compression Algorithms
341
342
### Extending Compression Registry
343
344
```java { .api }
345
// Custom compression algorithm implementation
346
public class CustomCompressionAlgorithm implements CompressionAlgorithm {
347
@Override
348
public String getId() {
349
return "CUSTOM";
350
}
351
352
@Override
353
public byte[] compress(byte[] payload) throws CompressionException {
354
// Custom compression implementation
355
return compressWithCustomAlgorithm(payload);
356
}
357
358
@Override
359
public byte[] decompress(byte[] compressed) throws CompressionException {
360
// Custom decompression implementation
361
return decompressWithCustomAlgorithm(compressed);
362
}
363
}
364
365
// Register custom algorithm
366
CompressionAlgorithm customAlg = new CustomCompressionAlgorithm();
367
368
// Use with parser
369
JwtParser customParser = Jwts.parser()
370
.verifyWith(key)
371
.zip() // Access compression registry
372
.add(customAlg)
373
.and()
374
.build();
375
376
// Use with builder
377
String customCompressedJWT = Jwts.builder()
378
.subject("user")
379
.claim("data", data)
380
.compressWith(customAlg)
381
.signWith(key)
382
.compact();
383
```
384
385
## Error Handling
386
387
### Compression Errors
388
389
```java { .api }
390
import io.jsonwebtoken.CompressionException;
391
392
try {
393
String compressedJWT = Jwts.builder()
394
.subject("user")
395
.claim("corruptData", potentiallyCorruptData)
396
.compressWith(Jwts.ZIP.DEF)
397
.signWith(key)
398
.compact();
399
400
} catch (CompressionException e) {
401
// Handle compression failure
402
log.error("Compression failed", e);
403
404
// Fallback to uncompressed JWT
405
String fallbackJWT = Jwts.builder()
406
.subject("user")
407
.claim("data", alternativeData)
408
.signWith(key)
409
.compact();
410
}
411
```
412
413
### Decompression Errors
414
415
```java { .api }
416
try {
417
Jws<Claims> jws = parser.parseSignedClaims(compressedJWT);
418
Claims claims = jws.getPayload();
419
420
} catch (CompressionException e) {
421
// Handle decompression failure
422
log.error("Decompression failed", e);
423
throw new SecurityException("Invalid compressed token", e);
424
425
} catch (Exception e) {
426
// Handle other parsing errors
427
log.error("Token parsing failed", e);
428
throw new IllegalArgumentException("Invalid token", e);
429
}
430
```
431
432
## Compression Best Practices
433
434
### When to Use Compression
435
436
```java { .api }
437
// Ideal candidates for compression:
438
// 1. Large claim sets
439
Map<String, Object> largeClaims = Map.of(
440
"permissions", Arrays.asList(/* many permissions */),
441
"userProfile", Map.of(/* detailed profile */),
442
"sessionData", Map.of(/* extensive session info */),
443
"preferences", Map.of(/* many user preferences */)
444
);
445
446
// 2. Repeated/structured data
447
List<Map<String, Object>> structuredData = Arrays.asList(
448
Map.of("id", 1, "name", "Item 1", "description", "Long description..."),
449
Map.of("id", 2, "name", "Item 2", "description", "Another long description..."),
450
// ... many similar items
451
);
452
453
// 3. JSON with repetitive keys
454
Map<String, Object> repetitiveData = Map.of(
455
"configuration", Map.of(
456
"feature_flag_1", true,
457
"feature_flag_2", false,
458
"feature_flag_3", true
459
// ... many feature flags
460
)
461
);
462
463
// Compression decision logic
464
public static boolean shouldCompress(Object payload) {
465
String json = serializeToJson(payload);
466
467
// Don't compress small payloads
468
if (json.length() < 200) return false;
469
470
// Always compress very large payloads
471
if (json.length() > 2000) return true;
472
473
// Analyze repetition for medium payloads
474
return hasHighRepetition(json);
475
}
476
```
477
478
### Performance Considerations
479
480
```java { .api }
481
// Pre-compress reusable content
482
public class JWTCompressionCache {
483
private final Map<String, byte[]> compressionCache = new ConcurrentHashMap<>();
484
485
public String createCachedCompressedJWT(String cacheKey, Object payload, SecretKey key) {
486
byte[] compressed = compressionCache.computeIfAbsent(cacheKey, k -> {
487
String json = serializeToJson(payload);
488
return Jwts.ZIP.DEF.compress(json.getBytes(StandardCharsets.UTF_8));
489
});
490
491
// Use pre-compressed content
492
return Jwts.builder()
493
.content(compressed)
494
.header()
495
.add("zip", "DEF") // Indicate compression
496
.and()
497
.signWith(key)
498
.compact();
499
}
500
}
501
```
502
503
The Compression functionality provides efficient payload reduction for JWTs while maintaining security and RFC compliance, with automatic handling in both creation and parsing scenarios.