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

utilities.mddocs/

0

# Utilities

1

2

The Utilities functionality in JJWT Implementation provides essential supporting components including cryptographic key utilities, Base64URL encoding/decoding, stream processing, service discovery, parameter validation, and registry management. These utilities enable the core JWT functionality while providing extensible infrastructure for custom implementations.

3

4

## Key Generation and Management

5

6

### Keys Utility Class

7

8

The `Keys` utility class provides secure key generation and management operations for JWT cryptographic operations.

9

10

```java { .api }

11

import io.jsonwebtoken.security.Keys;

12

import io.jsonwebtoken.security.Password;

13

import io.jsonwebtoken.security.SecretKeyBuilder;

14

import io.jsonwebtoken.security.PrivateKeyBuilder;

15

import javax.crypto.SecretKey;

16

import java.security.KeyPair;

17

import java.security.PrivateKey;

18

import java.security.Provider;

19

20

/**

21

* Utility class for securely generating SecretKeys and KeyPairs.

22

*/

23

public final class Keys {

24

25

/**

26

* Creates a new SecretKey instance for use with HMAC-SHA algorithms based on the specified key byte array.

27

* @param bytes the key byte array

28

* @return a new SecretKey instance for use with HMAC-SHA algorithms

29

* @throws WeakKeyException if the key byte array length is less than 256 bits (32 bytes)

30

*/

31

public static SecretKey hmacShaKeyFor(byte[] bytes) throws WeakKeyException;

32

33

/**

34

* Returns a new Password instance suitable for use with password-based key derivation algorithms.

35

* @param password the raw password character array to clone

36

* @return a new Password instance that wraps a new clone of the specified password character array

37

*/

38

public static Password password(char[] password);

39

40

/**

41

* Returns a SecretKeyBuilder that produces the specified key, allowing association with a Provider.

42

* @param key the secret key to use for cryptographic operations

43

* @return a new SecretKeyBuilder that produces the specified key

44

*/

45

public static SecretKeyBuilder builder(SecretKey key);

46

47

/**

48

* Returns a PrivateKeyBuilder that produces the specified key, allowing association with a PublicKey or Provider.

49

* @param key the private key to use for cryptographic operations

50

* @return a new PrivateKeyBuilder that produces the specified private key

51

*/

52

public static PrivateKeyBuilder builder(PrivateKey key);

53

}

54

```

55

56

### HMAC Key Creation

57

58

```java { .api }

59

// Create HMAC key from byte array

60

byte[] keyBytes = generateSecureRandomBytes(32); // 256 bits for HS256

61

SecretKey hmacKey = Keys.hmacShaKeyFor(keyBytes);

62

63

// Key strength validation - automatically selects appropriate HMAC algorithm

64

byte[] strongKeyBytes = generateSecureRandomBytes(64); // 512 bits

65

SecretKey strongKey = Keys.hmacShaKeyFor(strongKeyBytes); // Returns HmacSHA512

66

67

// Weak key handling

68

try {

69

byte[] weakKeyBytes = generateSecureRandomBytes(16); // Only 128 bits

70

SecretKey weakKey = Keys.hmacShaKeyFor(weakKeyBytes);

71

} catch (WeakKeyException e) {

72

// Handle insufficient key strength

73

System.err.println("Key too weak: " + e.getMessage());

74

// Use algorithm-specific key generation instead

75

SecretKey safeKey = Jwts.SIG.HS256.key().build();

76

}

77

```

78

79

### Password-Based Key Derivation

80

81

```java { .api }

82

// Create password for PBKDF2 operations

83

char[] passwordChars = "secure-password".toCharArray();

84

Password password = Keys.password(passwordChars);

85

86

// Use with password-based algorithms

87

SecretKey derivedKey = Jwts.KEY.PBES2_HS256_A128KW.key()

88

.password(password)

89

.build();

90

91

// Clear password after use for security

92

Arrays.fill(passwordChars, '\0');

93

password.destroy(); // Clear internal password copy

94

```

95

96

### Provider-Specific Key Handling

97

98

```java { .api }

99

// Associate secret key with specific JCA provider

100

Provider hsm = Security.getProvider("SunPKCS11-HSM");

101

SecretKey hsmKey = getKeyFromHSM(); // Hypothetical HSM key

102

103

SecretKey providerKey = Keys.builder(hsmKey)

104

.provider(hsm)

105

.build();

106

107

// Associate private key with public key and provider

108

PrivateKey privateKey = getPrivateKeyFromHSM();

109

PublicKey publicKey = getCorrespondingPublicKey();

110

111

PrivateKey enhancedPrivateKey = Keys.builder(privateKey)

112

.publicKey(publicKey)

113

.provider(hsm)

114

.build();

115

116

// Use in JWT operations

117

String jwt = Jwts.builder()

118

.subject("user")

119

.signWith(enhancedPrivateKey)

120

.compact();

121

```

122

123

### Modern Algorithm Integration

124

125

```java { .api }

126

// Recommended approach: Use algorithm-specific key generation

127

// Instead of Keys.secretKeyFor(SignatureAlgorithm.HS256) [deprecated]

128

SecretKey hs256Key = Jwts.SIG.HS256.key().build();

129

SecretKey hs384Key = Jwts.SIG.HS384.key().build();

130

SecretKey hs512Key = Jwts.SIG.HS512.key().build();

131

132

// Instead of Keys.keyPairFor(SignatureAlgorithm.RS256) [deprecated]

133

KeyPair rs256KeyPair = Jwts.SIG.RS256.keyPair().build();

134

KeyPair ecKeyPair = Jwts.SIG.ES256.keyPair().build();

135

KeyPair eddsaKeyPair = Jwts.SIG.EdDSA.keyPair().build();

136

137

// With custom provider and secure random

138

Provider customProvider = getCustomProvider();

139

SecureRandom secureRandom = getSecureRandom();

140

141

SecretKey customKey = Jwts.SIG.HS256.key()

142

.provider(customProvider)

143

.random(secureRandom)

144

.build();

145

```

146

147

## Base64URL Codec

148

149

### Base64UrlCodec Class

150

151

RFC 4648 compliant Base64URL encoding and decoding without padding.

152

153

```java { .api }

154

import io.jsonwebtoken.impl.Base64UrlCodec;

155

import java.nio.charset.StandardCharsets;

156

157

// Create codec instance

158

Base64UrlCodec codec = new Base64UrlCodec();

159

160

// Encode string to Base64URL

161

String text = "Hello, World!";

162

String encoded = codec.encode(text);

163

// Result: "SGVsbG8sIFdvcmxkIQ" (no padding)

164

165

// Encode byte array to Base64URL

166

byte[] data = "Binary data".getBytes(StandardCharsets.UTF_8);

167

String encodedBytes = codec.encode(data);

168

169

// Decode Base64URL to string

170

String decoded = codec.decodeToString(encoded);

171

// Result: "Hello, World!"

172

173

// Decode Base64URL to byte array

174

byte[] decodedBytes = codec.decode(encodedBytes);

175

String recovered = new String(decodedBytes, StandardCharsets.UTF_8);

176

```

177

178

### Base64URL vs Standard Base64

179

180

```java { .api }

181

// Demonstrate Base64URL differences

182

String testData = "Test data with special characters: +/=";

183

byte[] bytes = testData.getBytes(StandardCharsets.UTF_8);

184

185

// Standard Base64 (with padding and +/= characters)

186

String standardB64 = Base64.getEncoder().encodeToString(bytes);

187

// Contains: +, /, = characters

188

189

// Base64URL (no padding, URL-safe characters)

190

Base64UrlCodec urlCodec = new Base64UrlCodec();

191

String base64Url = urlCodec.encode(bytes);

192

// Uses: -, _ instead of +, / and no padding

193

194

// URL safety demonstration

195

String urlWithStandardB64 = "https://api.example.com/token?jwt=" + standardB64;

196

// Problematic: contains +/= that need URL encoding

197

198

String urlWithBase64Url = "https://api.example.com/token?jwt=" + base64Url;

199

// Safe: no characters requiring URL encoding

200

```

201

202

### Advanced Base64URL Operations

203

204

```java { .api }

205

// Handle different input types

206

Base64UrlCodec codec = new Base64UrlCodec();

207

208

// Encode various data types

209

String jsonData = "{\"sub\":\"user\",\"exp\":1234567890}";

210

String encodedJson = codec.encode(jsonData);

211

212

byte[] binaryData = {0x48, 0x65, 0x6C, 0x6C, 0x6F}; // "Hello" in bytes

213

String encodedBinary = codec.encode(binaryData);

214

215

// Large data handling

216

byte[] largeData = generateLargeByteArray(10000);

217

String encodedLarge = codec.encode(largeData);

218

byte[] decodedLarge = codec.decode(encodedLarge);

219

220

// Verify round-trip integrity

221

boolean integrityCheck = Arrays.equals(largeData, decodedLarge);

222

223

// Error handling

224

try {

225

String invalidBase64Url = "Invalid!!!Base64URL";

226

byte[] result = codec.decode(invalidBase64Url);

227

} catch (IllegalArgumentException e) {

228

// Handle invalid Base64URL input

229

log.error("Invalid Base64URL input", e);

230

}

231

```

232

233

## Stream Processing

234

235

### Streams Utility Class

236

237

Memory-efficient stream operations for handling large payloads.

238

239

```java { .api }

240

import io.jsonwebtoken.impl.io.Streams;

241

import java.io.InputStream;

242

import java.io.OutputStream;

243

import java.io.ByteArrayInputStream;

244

import java.io.ByteArrayOutputStream;

245

import java.io.FileInputStream;

246

import java.io.FileOutputStream;

247

248

// Copy streams efficiently

249

InputStream source = new FileInputStream("large-file.json");

250

OutputStream destination = new ByteArrayOutputStream();

251

252

// Copy with automatic resource management

253

long bytesCopied = Streams.copy(source, destination);

254

255

// Convert stream to byte array

256

InputStream dataStream = new ByteArrayInputStream("Stream data".getBytes());

257

byte[] streamBytes = Streams.bytes(dataStream);

258

259

// Handle large streams without loading everything into memory

260

InputStream largeStream = new FileInputStream("very-large-file.dat");

261

OutputStream output = new FileOutputStream("output-file.dat");

262

Streams.copy(largeStream, output);

263

```

264

265

### Stream-based JWT Operations

266

267

```java { .api }

268

// Create JWT from large stream content

269

InputStream largePayload = new FileInputStream("large-document.json");

270

271

String streamJwt = Jwts.builder()

272

.content(largePayload) // Stream directly without loading into memory

273

.header()

274

.contentType("application/json")

275

.and()

276

.signWith(secretKey)

277

.compact();

278

279

// Parse JWT with stream content

280

JwtParser parser = Jwts.parser()

281

.verifyWith(secretKey)

282

.build();

283

284

Jws<InputStream> streamJws = parser.parseSignedContent(streamJwt);

285

InputStream contentStream = streamJws.getPayload();

286

287

// Process stream content efficiently

288

try (InputStream content = contentStream) {

289

byte[] data = Streams.bytes(content);

290

processLargeData(data);

291

}

292

```

293

294

### Memory-Efficient Operations

295

296

```java { .api }

297

// Process large JWT content without memory issues

298

public static void processLargeJwtContent(String jwt, SecretKey key) {

299

JwtParser parser = Jwts.parser()

300

.verifyWith(key)

301

.build();

302

303

// Parse to stream to avoid loading entire payload

304

Jws<InputStream> jws = parser.parseSignedContent(jwt);

305

306

try (InputStream content = jws.getPayload()) {

307

// Process in chunks to manage memory

308

byte[] buffer = new byte[8192]; // 8KB buffer

309

int bytesRead;

310

311

while ((bytesRead = content.read(buffer)) != -1) {

312

processChunk(buffer, bytesRead);

313

}

314

} catch (IOException e) {

315

throw new RuntimeException("Failed to process JWT content", e);

316

}

317

}

318

319

private static void processChunk(byte[] buffer, int length) {

320

// Process data chunk without storing entire payload

321

String chunk = new String(buffer, 0, length, StandardCharsets.UTF_8);

322

// ... process chunk

323

}

324

```

325

326

## Service Discovery

327

328

### Services Utility Class

329

330

Service loader utility for implementation discovery and plugin architecture.

331

332

```java { .api }

333

import io.jsonwebtoken.impl.lang.Services;

334

import io.jsonwebtoken.io.Serializer;

335

import io.jsonwebtoken.io.Deserializer;

336

import io.jsonwebtoken.security.SecureDigestAlgorithm;

337

import java.util.Iterator;

338

import java.util.function.Predicate;

339

340

// Get first available service implementation

341

Serializer<Map<String, ?>> serializer = Services.get(Serializer.class);

342

343

// Get service with specific criteria

344

Predicate<Deserializer<Map<String, ?>>> jsonFilter =

345

deserializer -> deserializer.getClass().getSimpleName().contains("Jackson");

346

347

Deserializer<Map<String, ?>> jsonDeserializer =

348

Services.get(Deserializer.class, jsonFilter);

349

350

// Get all service implementations

351

Iterator<SecureDigestAlgorithm> algorithms =

352

Services.iterator(SecureDigestAlgorithm.class);

353

354

// Service availability check

355

boolean hasJacksonSupport = Services.get(Serializer.class) != null;

356

```

357

358

### Service Loading Examples

359

360

```java { .api }

361

// Load custom algorithm implementations

362

public static void loadCustomAlgorithms() {

363

// Service loader automatically discovers implementations

364

Iterator<SecureDigestAlgorithm> customAlgorithms =

365

Services.iterator(SecureDigestAlgorithm.class);

366

367

while (customAlgorithms.hasNext()) {

368

SecureDigestAlgorithm algorithm = customAlgorithms.next();

369

370

if (algorithm.getId().startsWith("CUSTOM_")) {

371

// Register custom algorithm

372

registerCustomAlgorithm(algorithm);

373

}

374

}

375

}

376

377

// Load serialization providers

378

public static Serializer<Map<String, ?>> loadBestSerializer() {

379

// Try Jackson first

380

Serializer<Map<String, ?>> jacksonSerializer =

381

Services.get(Serializer.class, s ->

382

s.getClass().getName().contains("jackson"));

383

384

if (jacksonSerializer != null) {

385

return jacksonSerializer;

386

}

387

388

// Fallback to any available serializer

389

return Services.get(Serializer.class);

390

}

391

392

// Service caching and reload

393

Services.reload(); // Clear service cache and reload

394

```

395

396

## Registry Management

397

398

### DefaultRegistry Class

399

400

Generic registry implementation for algorithm and component collections.

401

402

```java { .api }

403

import io.jsonwebtoken.impl.lang.DefaultRegistry;

404

import io.jsonwebtoken.security.SecureDigestAlgorithm;

405

import io.jsonwebtoken.CompressionAlgorithm;

406

407

// Create custom algorithm registry

408

DefaultRegistry<SecureDigestAlgorithm<?, ?>> customSigRegistry =

409

new DefaultRegistry<>("Custom Signature Algorithms");

410

411

// Add algorithms to registry

412

SecureDigestAlgorithm<?, ?> customAlgorithm = createCustomAlgorithm();

413

customSigRegistry.add(customAlgorithm);

414

415

// Registry operations

416

boolean hasAlgorithm = customSigRegistry.containsKey("CUSTOM_HS256");

417

SecureDigestAlgorithm<?, ?> algorithm = customSigRegistry.get("CUSTOM_HS256");

418

Set<String> algorithmIds = customSigRegistry.keySet();

419

Collection<SecureDigestAlgorithm<?, ?>> allAlgorithms = customSigRegistry.values();

420

421

// Registry with validation

422

SecureDigestAlgorithm<?, ?> validatedAlgorithm =

423

customSigRegistry.forKey("CUSTOM_HS256"); // Throws if not found

424

```

425

426

### Registry Integration

427

428

```java { .api }

429

// Extend existing registries

430

public class ExtendedSignatureRegistry extends DefaultRegistry<SecureDigestAlgorithm<?, ?>> {

431

432

public ExtendedSignatureRegistry() {

433

super("Extended Signature Algorithms");

434

435

// Add all standard algorithms

436

addAll(Jwts.SIG.get().values());

437

438

// Add custom algorithms

439

add(new CustomHMACAlgorithm("CUSTOM_HS256", 256));

440

add(new CustomRSAAlgorithm("CUSTOM_RS256"));

441

add(new CustomECAlgorithm("CUSTOM_ES256"));

442

}

443

}

444

445

// Use extended registry

446

ExtendedSignatureRegistry extendedSig = new ExtendedSignatureRegistry();

447

448

JwtParser extendedParser = Jwts.parser()

449

.verifyWith(secretKey)

450

.sig()

451

.add(extendedSig.get("CUSTOM_HS256"))

452

.and()

453

.build();

454

```

455

456

## Parameter Validation

457

458

### Parameters Utility Class

459

460

Type-safe parameter validation and assertion utilities.

461

462

```java { .api }

463

import io.jsonwebtoken.impl.lang.Parameters;

464

465

// Parameter validation examples

466

public static SecretKey validateSecretKey(SecretKey key, String algorithmId) {

467

// Check for null

468

Parameters.notNull(key, "Secret key cannot be null");

469

470

// Check key algorithm

471

String keyAlgorithm = key.getAlgorithm();

472

Parameters.notEmpty(keyAlgorithm, "Key algorithm cannot be empty");

473

474

// Validate key length

475

byte[] encoded = key.getEncoded();

476

Parameters.notEmpty(encoded, "Key must be encodable");

477

478

int bitLength = encoded.length * 8;

479

Parameters.gt(bitLength, 255, "Key must be at least 256 bits");

480

481

return key;

482

}

483

484

// String parameter validation

485

public static String validateKeyId(String keyId) {

486

Parameters.notEmpty(keyId, "Key ID cannot be null or empty");

487

Parameters.maxLength(keyId, 255, "Key ID too long");

488

489

// Custom validation

490

if (!keyId.matches("^[a-zA-Z0-9_-]+$")) {

491

throw new IllegalArgumentException("Invalid key ID format");

492

}

493

494

return keyId;

495

}

496

497

// Collection validation

498

public static <T> List<T> validateList(List<T> list, String paramName) {

499

Parameters.notNull(list, paramName + " cannot be null");

500

Parameters.notEmpty(list, paramName + " cannot be empty");

501

502

// Validate elements

503

for (int i = 0; i < list.size(); i++) {

504

Parameters.notNull(list.get(i), paramName + "[" + i + "] cannot be null");

505

}

506

507

return list;

508

}

509

```

510

511

### Advanced Parameter Validation

512

513

```java { .api }

514

// Complex parameter validation patterns

515

public static KeyPair validateKeyPairForAlgorithm(KeyPair keyPair, String algorithm) {

516

Parameters.notNull(keyPair, "KeyPair cannot be null");

517

Parameters.notNull(keyPair.getPublic(), "Public key cannot be null");

518

Parameters.notNull(keyPair.getPrivate(), "Private key cannot be null");

519

520

// Algorithm-specific validation

521

if (algorithm.startsWith("RS") || algorithm.startsWith("PS")) {

522

// RSA validation

523

Parameters.eq(keyPair.getPublic().getAlgorithm(), "RSA",

524

"Algorithm " + algorithm + " requires RSA keys");

525

526

// Check key size

527

RSAPublicKey rsaPublic = (RSAPublicKey) keyPair.getPublic();

528

int keySize = rsaPublic.getModulus().bitLength();

529

Parameters.gte(keySize, 2048, "RSA keys must be at least 2048 bits");

530

531

} else if (algorithm.startsWith("ES")) {

532

// EC validation

533

Parameters.eq(keyPair.getPublic().getAlgorithm(), "EC",

534

"Algorithm " + algorithm + " requires EC keys");

535

}

536

537

return keyPair;

538

}

539

540

// Conditional validation

541

public static void validateJWEParameters(Key kek, String keyAlg, String encAlg) {

542

Parameters.notNull(kek, "Key encryption key cannot be null");

543

Parameters.notEmpty(keyAlg, "Key algorithm cannot be empty");

544

Parameters.notEmpty(encAlg, "Encryption algorithm cannot be empty");

545

546

// Validate key compatibility with algorithm

547

if (keyAlg.startsWith("RSA")) {

548

Parameters.isTrue(kek instanceof PublicKey || kek instanceof PrivateKey,

549

"RSA algorithms require asymmetric keys");

550

} else if (keyAlg.contains("KW")) {

551

Parameters.isTrue(kek instanceof SecretKey,

552

"Key wrap algorithms require symmetric keys");

553

}

554

}

555

```

556

557

## Function Utilities

558

559

### Functions Class

560

561

Common functional utilities and constants.

562

563

```java { .api }

564

import io.jsonwebtoken.impl.lang.Functions;

565

import java.util.function.Function;

566

import java.util.function.Predicate;

567

568

// Common function constants and utilities

569

// (Specific implementations depend on the Functions class content)

570

571

// Example usage patterns for functional operations

572

public static <T> List<T> filterAndTransform(List<T> input,

573

Predicate<T> filter,

574

Function<T, T> transformer) {

575

return input.stream()

576

.filter(filter)

577

.map(transformer)

578

.collect(Collectors.toList());

579

}

580

581

// Functional JWT processing

582

public static List<Claims> extractClaimsFromTokens(List<String> tokens,

583

SecretKey key) {

584

JwtParser parser = Jwts.parser().verifyWith(key).build();

585

586

return tokens.stream()

587

.map(token -> {

588

try {

589

return parser.parseSignedClaims(token).getPayload();

590

} catch (Exception e) {

591

return null; // Filter out invalid tokens

592

}

593

})

594

.filter(Objects::nonNull)

595

.collect(Collectors.toList());

596

}

597

```

598

599

## Clock Utilities

600

601

### FixedClock Implementation

602

603

Testing utility for fixed-time scenarios.

604

605

```java { .api }

606

import io.jsonwebtoken.impl.FixedClock;

607

import io.jsonwebtoken.Clock;

608

import java.time.Instant;

609

import java.util.Date;

610

611

// Create fixed clock for testing

612

Date fixedTime = Date.from(Instant.parse("2024-01-01T12:00:00Z"));

613

Clock fixedClock = new FixedClock(fixedTime);

614

615

// Use fixed clock in JWT operations

616

JwtParser testParser = Jwts.parser()

617

.verifyWith(secretKey)

618

.clock(fixedClock) // All time-based validations use fixed time

619

.build();

620

621

// Create JWT with fixed issuedAt

622

String testJwt = Jwts.builder()

623

.subject("test-user")

624

.issuedAt(fixedClock.now()) // Uses fixed time

625

.expiration(new Date(fixedTime.getTime() + 3600000)) // 1 hour later

626

.signWith(secretKey)

627

.compact();

628

629

// Test time-based scenarios

630

public static void testTokenExpiration() {

631

Date now = Date.from(Instant.parse("2024-01-01T12:00:00Z"));

632

Date expiry = Date.from(Instant.parse("2024-01-01T13:00:00Z"));

633

634

// Create token

635

Clock createTime = new FixedClock(now);

636

String jwt = Jwts.builder()

637

.subject("user")

638

.issuedAt(createTime.now())

639

.expiration(expiry)

640

.signWith(secretKey)

641

.compact();

642

643

// Test parsing at different times

644

Clock beforeExpiry = new FixedClock(Date.from(Instant.parse("2024-01-01T12:30:00Z")));

645

Clock afterExpiry = new FixedClock(Date.from(Instant.parse("2024-01-01T14:00:00Z")));

646

647

// Should succeed

648

JwtParser validParser = Jwts.parser()

649

.verifyWith(secretKey)

650

.clock(beforeExpiry)

651

.build();

652

653

Claims validClaims = validParser.parseSignedClaims(jwt).getPayload();

654

655

// Should fail with ExpiredJwtException

656

JwtParser expiredParser = Jwts.parser()

657

.verifyWith(secretKey)

658

.clock(afterExpiry)

659

.build();

660

661

try {

662

expiredParser.parseSignedClaims(jwt);

663

fail("Should have thrown ExpiredJwtException");

664

} catch (ExpiredJwtException e) {

665

// Expected

666

}

667

}

668

```

669

670

## Performance Utilities

671

672

### Optimization Patterns

673

674

```java { .api }

675

// Reusable component caching

676

public class JWTUtilityCache {

677

private static final Base64UrlCodec CODEC = new Base64UrlCodec();

678

private static final Map<String, JwtParser> PARSER_CACHE = new ConcurrentHashMap<>();

679

680

public static String encodePayload(Object payload) {

681

String json = serializeToJson(payload);

682

return CODEC.encode(json);

683

}

684

685

public static JwtParser getCachedParser(String keyId, Key key) {

686

return PARSER_CACHE.computeIfAbsent(keyId, k ->

687

Jwts.parser().verifyWith(key).build()

688

);

689

}

690

691

public static void clearCache() {

692

PARSER_CACHE.clear();

693

}

694

}

695

696

// Batch processing utilities

697

public static Map<String, Claims> parseTokenBatch(List<String> tokens,

698

Map<String, Key> keyMap) {

699

return tokens.parallelStream()

700

.collect(Collectors.toConcurrentMap(

701

token -> token, // Use token as key

702

token -> {

703

try {

704

// Extract key ID from header

705

String keyId = extractKeyIdFromToken(token);

706

Key key = keyMap.get(keyId);

707

708

if (key != null) {

709

JwtParser parser = JWTUtilityCache.getCachedParser(keyId, key);

710

return parser.parseSignedClaims(token).getPayload();

711

}

712

return null;

713

} catch (Exception e) {

714

return null; // Skip invalid tokens

715

}

716

},

717

(existing, replacement) -> existing, // Keep first valid result

718

ConcurrentHashMap::new

719

)).entrySet().stream()

720

.filter(entry -> entry.getValue() != null)

721

.collect(Collectors.toMap(

722

Map.Entry::getKey,

723

Map.Entry::getValue

724

));

725

}

726

```

727

728

## Input/Output (IO) Package

729

730

The IO package provides interfaces and utilities for encoding, decoding, serialization, and deserialization operations used throughout JJWT.

731

732

### Core IO Interfaces

733

734

```java { .api }

735

import io.jsonwebtoken.io.Encoder;

736

import io.jsonwebtoken.io.Decoder;

737

import io.jsonwebtoken.io.Serializer;

738

import io.jsonwebtoken.io.Deserializer;

739

import io.jsonwebtoken.io.Parser;

740

import java.io.InputStream;

741

import java.io.OutputStream;

742

import java.util.Map;

743

744

/**

745

* An encoder converts data of one type into another formatted data value.

746

*/

747

public interface Encoder<T, R> {

748

/**

749

* Convert the specified data into another formatted data value.

750

* @param t the data to convert

751

* @return the converted data

752

*/

753

R encode(T t);

754

}

755

756

/**

757

* A decoder converts formatted data of one type into another data type.

758

*/

759

public interface Decoder<T, R> {

760

/**

761

* Convert the specified formatted data into another data value.

762

* @param t the formatted data to convert

763

* @return the converted data

764

*/

765

R decode(T t);

766

}

767

768

/**

769

* A Serializer is able to convert a Java object into a formatted byte stream.

770

*/

771

public interface Serializer<T> {

772

/**

773

* Converts the specified Java object into a formatted data byte array.

774

* @param t the Java object to convert

775

* @return the formatted data as a byte array

776

*/

777

byte[] serialize(T t);

778

779

/**

780

* Converts the specified Java object into a formatted data stream.

781

* @param t the Java object to convert

782

* @param out the OutputStream to write to

783

*/

784

void serialize(T t, OutputStream out);

785

}

786

787

/**

788

* A Deserializer is able to convert formatted byte data back into a Java object.

789

*/

790

public interface Deserializer<T> {

791

/**

792

* Convert the specified formatted data byte array into a Java object.

793

* @param data the formatted data bytes

794

* @return the reconstituted Java object

795

*/

796

T deserialize(byte[] data);

797

798

/**

799

* Convert the specified formatted data stream into a Java object.

800

* @param in the InputStream to read from

801

* @return the reconstituted Java object

802

*/

803

T deserialize(InputStream in);

804

}

805

806

/**

807

* A Parser converts data from one format to another.

808

*/

809

public interface Parser<T> {

810

/**

811

* Parse the specified value into the expected Java object.

812

* @param value the formatted value to parse

813

* @return the parsed Java object

814

*/

815

T parse(CharSequence value);

816

}

817

```

818

819

### Base64 Encoding and Decoding

820

821

```java { .api }

822

import io.jsonwebtoken.io.Encoders;

823

import io.jsonwebtoken.io.Decoders;

824

import io.jsonwebtoken.io.Base64Encoder;

825

import io.jsonwebtoken.io.Base64Decoder;

826

827

// Standard Base64 encoding/decoding

828

Base64Encoder base64Encoder = Encoders.BASE64;

829

Base64Decoder base64Decoder = Decoders.BASE64;

830

831

String originalData = "Hello, World!";

832

String encoded = base64Encoder.encode(originalData);

833

String decoded = base64Decoder.decode(encoded);

834

835

// Base64URL encoding/decoding (JWT standard)

836

Base64Encoder base64UrlEncoder = Encoders.BASE64URL;

837

Base64Decoder base64UrlDecoder = Decoders.BASE64URL;

838

839

String urlSafeEncoded = base64UrlEncoder.encode(originalData);

840

String urlSafeDecoded = base64UrlDecoder.decode(urlSafeEncoded);

841

842

// Binary data encoding

843

byte[] binaryData = "Binary content".getBytes(StandardCharsets.UTF_8);

844

String encodedBinary = base64UrlEncoder.encode(binaryData);

845

byte[] decodedBinary = base64UrlDecoder.decodeToBytes(encodedBinary);

846

```

847

848

### JSON Serialization

849

850

```java { .api }

851

// Use with JWT builder for custom JSON serialization

852

Map<String, Object> customPayload = new HashMap<>();

853

customPayload.put("user_id", 12345);

854

customPayload.put("roles", Arrays.asList("admin", "user"));

855

customPayload.put("metadata", Map.of("department", "engineering"));

856

857

Serializer<Map<String, ?>> jsonSerializer = getJsonSerializer();

858

859

String jwt = Jwts.builder()

860

.claims(customPayload)

861

.json(jsonSerializer) // Use custom JSON serializer

862

.signWith(secretKey)

863

.compact();

864

865

// Use with JWT parser for custom JSON deserialization

866

Deserializer<Map<String, ?>> jsonDeserializer = getJsonDeserializer();

867

868

JwtParser parser = Jwts.parser()

869

.verifyWith(secretKey)

870

.json(jsonDeserializer) // Use custom JSON deserializer

871

.build();

872

873

Jws<Claims> jws = parser.parseSignedClaims(jwt);

874

```

875

876

### Stream-Based Operations

877

878

```java { .api }

879

// Custom serializer for large payloads

880

public class StreamingJsonSerializer implements Serializer<Map<String, ?>> {

881

882

@Override

883

public byte[] serialize(Map<String, ?> map) {

884

ByteArrayOutputStream baos = new ByteArrayOutputStream();

885

serialize(map, baos);

886

return baos.toByteArray();

887

}

888

889

@Override

890

public void serialize(Map<String, ?> map, OutputStream out) {

891

try (JsonGenerator generator = createJsonGenerator(out)) {

892

generator.writeStartObject();

893

for (Map.Entry<String, ?> entry : map.entrySet()) {

894

generator.writeObjectField(entry.getKey(), entry.getValue());

895

}

896

generator.writeEndObject();

897

} catch (IOException e) {

898

throw new SerializationException("JSON serialization failed", e);

899

}

900

}

901

}

902

903

// Custom deserializer for streaming

904

public class StreamingJsonDeserializer implements Deserializer<Map<String, ?>> {

905

906

@Override

907

public Map<String, ?> deserialize(byte[] data) {

908

return deserialize(new ByteArrayInputStream(data));

909

}

910

911

@Override

912

public Map<String, ?> deserialize(InputStream in) {

913

try (JsonParser parser = createJsonParser(in)) {

914

return parseJsonObject(parser);

915

} catch (IOException e) {

916

throw new DeserializationException("JSON deserialization failed", e);

917

}

918

}

919

}

920

```

921

922

### IO Exception Types

923

924

```java { .api }

925

import io.jsonwebtoken.io.IOException;

926

import io.jsonwebtoken.io.SerializationException;

927

import io.jsonwebtoken.io.DeserializationException;

928

import io.jsonwebtoken.io.DecodingException;

929

930

/**

931

* Base IO exception for all input/output related errors.

932

*/

933

public class IOException extends RuntimeException;

934

935

/**

936

* Exception thrown when object serialization fails.

937

*/

938

public class SerializationException extends IOException;

939

940

/**

941

* Exception thrown when data deserialization fails.

942

*/

943

public class DeserializationException extends IOException;

944

945

/**

946

* Exception thrown when data decoding fails.

947

*/

948

public class DecodingException extends IOException;

949

950

// Exception handling in custom serializers

951

public class SafeJsonSerializer implements Serializer<Map<String, ?>> {

952

953

@Override

954

public byte[] serialize(Map<String, ?> map) {

955

try {

956

return performSerialization(map);

957

} catch (Exception e) {

958

throw new SerializationException("Failed to serialize JSON: " + e.getMessage(), e);

959

}

960

}

961

962

@Override

963

public void serialize(Map<String, ?> map, OutputStream out) {

964

try {

965

performStreamSerialization(map, out);

966

} catch (Exception e) {

967

throw new SerializationException("Failed to serialize JSON to stream: " + e.getMessage(), e);

968

}

969

}

970

}

971

```

972

973

### Custom Parser Implementation

974

975

```java { .api }

976

// Custom parser for special JWT formats

977

public class CustomJwtFormatParser implements Parser<Jwt<?, ?>> {

978

979

private final JwtParser delegate;

980

981

public CustomJwtFormatParser(JwtParser delegate) {

982

this.delegate = delegate;

983

}

984

985

@Override

986

public Jwt<?, ?> parse(CharSequence value) {

987

// Pre-process custom format

988

String standardJwt = convertCustomFormatToStandard(value.toString());

989

990

// Delegate to standard parser

991

return delegate.parse(standardJwt);

992

}

993

994

private String convertCustomFormatToStandard(String customFormat) {

995

// Implementation-specific conversion logic

996

if (customFormat.startsWith("CUSTOM:")) {

997

return customFormat.substring(7); // Remove custom prefix

998

}

999

return customFormat;

1000

}

1001

}

1002

1003

// Usage with custom parser

1004

Parser<Jwt<?, ?>> customParser = new CustomJwtFormatParser(

1005

Jwts.parser()

1006

.verifyWith(secretKey)

1007

.build()

1008

);

1009

1010

Jwt<?, ?> jwt = customParser.parse("CUSTOM:eyJ0eXAiOiJKV1QiLCJhbGc...");

1011

```

1012

1013

## Supporting Type Definitions

1014

1015

### Core Interface Types

1016

1017

```java { .api }

1018

import io.jsonwebtoken.Clock;

1019

import io.jsonwebtoken.Locator;

1020

import io.jsonwebtoken.Identifiable;

1021

import io.jsonwebtoken.security.SecretKeyBuilder;

1022

import io.jsonwebtoken.security.PrivateKeyBuilder;

1023

import io.jsonwebtoken.security.Password;

1024

import java.util.Date;

1025

import java.security.Key;

1026

1027

/**

1028

* Clock interface for time operations.

1029

*/

1030

public interface Clock {

1031

/**

1032

* Returns the current time as a Date.

1033

* @return the current time

1034

*/

1035

Date now();

1036

}

1037

1038

/**

1039

* Locator interface for resource location operations.

1040

*/

1041

public interface Locator<T> {

1042

/**

1043

* Locates a resource based on the provided context.

1044

* @param header JWT header providing context

1045

* @return the located resource

1046

*/

1047

T locate(JwsHeader header);

1048

}

1049

1050

/**

1051

* Identifiable interface for objects with string identifiers.

1052

*/

1053

public interface Identifiable {

1054

/**

1055

* Returns the string identifier of this object.

1056

* @return the string identifier

1057

*/

1058

String getId();

1059

}

1060

1061

/**

1062

* Builder for SecretKey instances with provider support.

1063

*/

1064

public interface SecretKeyBuilder extends Builder<SecretKey> {

1065

/**

1066

* Associates a Provider that must be used with the key.

1067

* @param provider the JCA Provider

1068

* @return this builder for method chaining

1069

*/

1070

SecretKeyBuilder provider(Provider provider);

1071

}

1072

1073

/**

1074

* Builder for PrivateKey instances with public key and provider support.

1075

*/

1076

public interface PrivateKeyBuilder extends Builder<PrivateKey> {

1077

/**

1078

* Associates a public key with the private key.

1079

* @param publicKey the corresponding public key

1080

* @return this builder for method chaining

1081

*/

1082

PrivateKeyBuilder publicKey(PublicKey publicKey);

1083

1084

/**

1085

* Associates a Provider that must be used with the key.

1086

* @param provider the JCA Provider

1087

* @return this builder for method chaining

1088

*/

1089

PrivateKeyBuilder provider(Provider provider);

1090

}

1091

1092

/**

1093

* Password interface for password-based key derivation.

1094

*/

1095

public interface Password extends Key {

1096

/**

1097

* Returns the password as a character array.

1098

* @return the password characters

1099

*/

1100

char[] toCharArray();

1101

1102

/**

1103

* Destroys this password by clearing its internal state.

1104

*/

1105

void destroy();

1106

}

1107

```

1108

1109

### Visitor Pattern Types

1110

1111

```java { .api }

1112

import io.jsonwebtoken.JwtVisitor;

1113

import io.jsonwebtoken.SupportedJwtVisitor;

1114

1115

/**

1116

* Visitor interface for processing different JWT types.

1117

*/

1118

public interface JwtVisitor<T> {

1119

/**

1120

* Visit an unsecured JWT with content payload.

1121

* @param jwt the unsecured content JWT

1122

* @return visitor result

1123

*/

1124

T visit(Jwt<Header, byte[]> jwt);

1125

1126

/**

1127

* Visit an unsecured JWT with claims payload.

1128

* @param jwt the unsecured claims JWT

1129

* @return visitor result

1130

*/

1131

T visit(Jwt<Header, Claims> jwt);

1132

1133

/**

1134

* Visit a signed JWT with content payload.

1135

* @param jws the signed content JWT

1136

* @return visitor result

1137

*/

1138

T visit(Jws<byte[]> jws);

1139

1140

/**

1141

* Visit a signed JWT with claims payload.

1142

* @param jws the signed claims JWT

1143

* @return visitor result

1144

*/

1145

T visit(Jws<Claims> jws);

1146

1147

/**

1148

* Visit an encrypted JWT with content payload.

1149

* @param jwe the encrypted content JWT

1150

* @return visitor result

1151

*/

1152

T visit(Jwe<byte[]> jwe);

1153

1154

/**

1155

* Visit an encrypted JWT with claims payload.

1156

* @param jwe the encrypted claims JWT

1157

* @return visitor result

1158

*/

1159

T visit(Jwe<Claims> jwe);

1160

}

1161

1162

/**

1163

* Base visitor implementation with default unsupported operation responses.

1164

*/

1165

public abstract class SupportedJwtVisitor<T> implements JwtVisitor<T> {

1166

1167

/**

1168

* Default message for unsupported operations.

1169

*/

1170

public static final String UNSUPPORTED_MSG = "Unsupported JWT type.";

1171

1172

@Override

1173

public T visit(Jwt<Header, byte[]> jwt) {

1174

throw new UnsupportedJwtException(UNSUPPORTED_MSG);

1175

}

1176

1177

@Override

1178

public T visit(Jwt<Header, Claims> jwt) {

1179

throw new UnsupportedJwtException(UNSUPPORTED_MSG);

1180

}

1181

1182

@Override

1183

public T visit(Jws<byte[]> jws) {

1184

throw new UnsupportedJwtException(UNSUPPORTED_MSG);

1185

}

1186

1187

@Override

1188

public T visit(Jws<Claims> jws) {

1189

throw new UnsupportedJwtException(UNSUPPORTED_MSG);

1190

}

1191

1192

@Override

1193

public T visit(Jwe<byte[]> jwe) {

1194

throw new UnsupportedJwtException(UNSUPPORTED_MSG);

1195

}

1196

1197

@Override

1198

public T visit(Jwe<Claims> jwe) {

1199

throw new UnsupportedJwtException(UNSUPPORTED_MSG);

1200

}

1201

}

1202

1203

// Example visitor implementation

1204

public class JwtTypeExtractor extends SupportedJwtVisitor<String> {

1205

1206

@Override

1207

public String visit(Jwt<Header, Claims> jwt) {

1208

return "unsecured-claims";

1209

}

1210

1211

@Override

1212

public String visit(Jws<Claims> jws) {

1213

return "signed-claims";

1214

}

1215

1216

@Override

1217

public String visit(Jwe<Claims> jwe) {

1218

return "encrypted-claims";

1219

}

1220

}

1221

1222

// Usage with visitor pattern

1223

JwtTypeExtractor extractor = new JwtTypeExtractor();

1224

Jwt<?, ?> someJwt = parser.parse(token);

1225

String jwtType = someJwt.accept(extractor);

1226

```

1227

1228

### Registry and Collection Types

1229

1230

```java { .api }

1231

import io.jsonwebtoken.lang.Registry;

1232

import io.jsonwebtoken.lang.NestedCollection;

1233

1234

/**

1235

* Registry interface for algorithm and component lookup.

1236

*/

1237

public interface Registry<K, V> extends Map<K, V> {

1238

/**

1239

* Returns the value associated with the specified key.

1240

* @param key the key to look up

1241

* @return the associated value

1242

*/

1243

V forKey(K key);

1244

1245

/**

1246

* Returns all values in the registry.

1247

* @return collection of all values

1248

*/

1249

Collection<V> values();

1250

}

1251

1252

/**

1253

* Nested collection interface for fluent configuration.

1254

*/

1255

public interface NestedCollection<T, P> {

1256

/**

1257

* Add an item to the collection.

1258

* @param item the item to add

1259

* @return this collection for chaining

1260

*/

1261

NestedCollection<T, P> add(T item);

1262

1263

/**

1264

* Remove an item from the collection.

1265

* @param item the item to remove

1266

* @return this collection for chaining

1267

*/

1268

NestedCollection<T, P> remove(T item);

1269

1270

/**

1271

* Return to the parent builder.

1272

* @return the parent builder

1273

*/

1274

P and();

1275

}

1276

```

1277

1278

The Utilities implementation provides robust, performance-optimized supporting functionality that enables the core JWT operations while maintaining extensibility and proper error handling.