or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

compression.mdindex.mdjwk-support.mdjwt-building.mdjwt-parsing.mdsecurity-algorithms.mdutilities.md

compression.mddocs/

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.