0
# JWT Parsing
1
2
The JWT Parsing functionality in JJWT Implementation centers around the `DefaultJwtParser` and `DefaultJwtParserBuilder` classes, providing comprehensive parsing, validation, and verification capabilities for JWT, JWS, and JWE tokens. The parser supports flexible configuration for security policies, key resolution, and validation rules.
3
4
## Core Parser Classes
5
6
### DefaultJwtParserBuilder
7
8
The configurable factory for creating JWT parsers with specific validation and security requirements.
9
10
```java { .api }
11
import io.jsonwebtoken.Jwts;
12
import io.jsonwebtoken.JwtParser;
13
import io.jsonwebtoken.JwtParserBuilder;
14
import io.jsonwebtoken.Claims;
15
import io.jsonwebtoken.Jws;
16
import io.jsonwebtoken.Jwe;
17
import io.jsonwebtoken.Locator;
18
import io.jsonwebtoken.Clock;
19
import javax.crypto.SecretKey;
20
import java.security.PublicKey;
21
import java.security.PrivateKey;
22
import java.security.Provider;
23
import java.util.Date;
24
25
// Basic parser creation
26
JwtParserBuilder parserBuilder = Jwts.parser();
27
28
// Parser with verification key
29
JwtParser parser = Jwts.parser()
30
.verifyWith(secretKey)
31
.build();
32
33
// Parser with decryption key
34
JwtParser decryptParser = Jwts.parser()
35
.decryptWith(privateKey)
36
.build();
37
```
38
39
### DefaultJwtParser
40
41
The main parsing engine that handles JWT, JWS, and JWE token processing.
42
43
```java { .api }
44
import io.jsonwebtoken.impl.DefaultJwtParser;
45
46
// Create parser instance
47
JwtParser parser = Jwts.parser()
48
.verifyWith(verificationKey)
49
.build();
50
51
// Token type detection
52
String token = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9...";
53
boolean isSigned = parser.isSigned(token);
54
55
// Generic parsing (returns appropriate type based on token)
56
Object result = parser.parse(token);
57
```
58
59
## Basic Parsing Operations
60
61
### Unsecured JWT Parsing
62
63
```java { .api }
64
// Parse unsecured JWT with claims
65
JwtParser unsecuredParser = Jwts.parser()
66
.unsecured() // Allow unsecured JWTs
67
.build();
68
69
String unsecuredToken = "eyJ0eXAiOiJKV1QiLCJhbGciOiJub25lIn0...";
70
71
Jwt<Claims> jwt = unsecuredParser.parseClaimsJwt(unsecuredToken);
72
Claims claims = jwt.getPayload();
73
74
String subject = claims.getSubject();
75
String issuer = claims.getIssuer();
76
Date expiration = claims.getExpiration();
77
78
// Parse unsecured JWT with content payload
79
Jwt<String> contentJwt = unsecuredParser.parseContentJwt(contentToken);
80
String content = contentJwt.getPayload();
81
```
82
83
### JWS Parsing (Signed JWT)
84
85
```java { .api }
86
// HMAC signature verification
87
SecretKey hmacKey = getHmacKey();
88
JwtParser hmacParser = Jwts.parser()
89
.verifyWith(hmacKey)
90
.build();
91
92
String signedToken = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9...";
93
94
Jws<Claims> jws = hmacParser.parseSignedClaims(signedToken);
95
Claims verifiedClaims = jws.getPayload();
96
97
// Access signature information
98
String algorithm = jws.getHeader().getAlgorithm();
99
String keyId = jws.getHeader().getKeyId();
100
101
// RSA signature verification
102
PublicKey rsaPublicKey = getRsaPublicKey();
103
JwtParser rsaParser = Jwts.parser()
104
.verifyWith(rsaPublicKey)
105
.build();
106
107
Jws<Claims> rsaJws = rsaParser.parseSignedClaims(rsaSignedToken);
108
109
// EC signature verification
110
PublicKey ecPublicKey = getEcPublicKey();
111
JwtParser ecParser = Jwts.parser()
112
.verifyWith(ecPublicKey)
113
.build();
114
115
Jws<Claims> ecJws = ecParser.parseSignedClaims(ecSignedToken);
116
```
117
118
### JWE Parsing (Encrypted JWT)
119
120
```java { .api }
121
// Direct decryption
122
SecretKey contentKey = getContentEncryptionKey();
123
JwtParser directParser = Jwts.parser()
124
.decryptWith(contentKey)
125
.build();
126
127
String encryptedToken = "eyJhbGciOiJkaXIiLCJlbmMiOiJBMjU2R0NNIn0...";
128
129
Jwe<Claims> jwe = directParser.parseEncryptedClaims(encryptedToken);
130
Claims decryptedClaims = jwe.getPayload();
131
132
// Key wrapping decryption
133
SecretKey keyEncryptionKey = getKeyEncryptionKey();
134
JwtParser kwParser = Jwts.parser()
135
.decryptWith(keyEncryptionKey)
136
.build();
137
138
Jwe<Claims> kwJwe = kwParser.parseEncryptedClaims(keyWrappedToken);
139
140
// RSA decryption
141
PrivateKey rsaPrivateKey = getRsaPrivateKey();
142
JwtParser rsaDecryptParser = Jwts.parser()
143
.decryptWith(rsaPrivateKey)
144
.build();
145
146
Jwe<Claims> rsaJwe = rsaDecryptParser.parseEncryptedClaims(rsaEncryptedToken);
147
```
148
149
## Advanced Parser Configuration
150
151
### Key Locators
152
153
```java { .api }
154
import io.jsonwebtoken.Locator;
155
import io.jsonwebtoken.ProtectedHeader;
156
157
// Dynamic key resolution based on header information
158
Locator<Key> keyLocator = new Locator<Key>() {
159
@Override
160
public Key locate(ProtectedHeader header) {
161
String keyId = header.getKeyId();
162
String algorithm = header.getAlgorithm();
163
164
if ("HS256".equals(algorithm)) {
165
return getHmacKeyById(keyId);
166
} else if ("RS256".equals(algorithm)) {
167
return getRsaPublicKeyById(keyId);
168
} else if ("ES256".equals(algorithm)) {
169
return getEcPublicKeyById(keyId);
170
}
171
172
throw new SecurityException("Unsupported algorithm: " + algorithm);
173
}
174
};
175
176
JwtParser dynamicParser = Jwts.parser()
177
.keyLocator(keyLocator)
178
.build();
179
180
// Parse with dynamic key resolution
181
Jws<Claims> dynamicJws = dynamicParser.parseSignedClaims(tokenWithKeyId);
182
```
183
184
### Clock Configuration
185
186
```java { .api }
187
import io.jsonwebtoken.Clock;
188
import java.time.Instant;
189
190
// Custom clock for testing or specific time zones
191
Clock customClock = () -> Date.from(Instant.parse("2024-01-01T12:00:00Z"));
192
193
JwtParser clockParser = Jwts.parser()
194
.verifyWith(secretKey)
195
.clock(customClock)
196
.build();
197
198
// Clock skew tolerance
199
JwtParser tolerantParser = Jwts.parser()
200
.verifyWith(secretKey)
201
.clockSkewSeconds(300) // Allow 5 minutes clock skew
202
.build();
203
204
Jws<Claims> tolerantJws = tolerantParser.parseSignedClaims(tokenWithTimeSkew);
205
```
206
207
### Algorithm Registry Configuration
208
209
```java { .api }
210
// Configure supported signature algorithms
211
JwtParser sigParser = Jwts.parser()
212
.verifyWith(secretKey)
213
.sig() // Access signature algorithm registry
214
.add(customSignatureAlgorithm)
215
.and()
216
.build();
217
218
// Configure supported encryption algorithms
219
JwtParser encParser = Jwts.parser()
220
.decryptWith(decryptionKey)
221
.enc() // Access encryption algorithm registry
222
.add(customEncryptionAlgorithm)
223
.and()
224
.key() // Access key algorithm registry
225
.add(customKeyAlgorithm)
226
.and()
227
.build();
228
229
// Configure compression algorithms
230
JwtParser zipParser = Jwts.parser()
231
.verifyWith(secretKey)
232
.zip() // Access compression algorithm registry
233
.add(customCompressionAlgorithm)
234
.and()
235
.build();
236
```
237
238
### Claims Requirements and Validation
239
240
The JwtParserBuilder provides comprehensive methods for requiring specific claim values during parsing.
241
242
```java { .api }
243
// Require specific standard claims
244
JwtParser requiredClaimsParser = Jwts.parser()
245
.verifyWith(secretKey)
246
.requireId("unique-token-id") // Require specific 'jti' claim
247
.requireSubject("john.doe") // Require specific 'sub' claim
248
.requireIssuer("https://auth.example.com") // Require specific 'iss' claim
249
.requireAudience("api.example.com") // Require specific 'aud' claim
250
.requireIssuedAt(specificIssuedAtDate) // Require specific 'iat' claim
251
.requireExpiration(specificExpirationDate) // Require specific 'exp' claim
252
.requireNotBefore(specificNotBeforeDate) // Require specific 'nbf' claim
253
.build();
254
255
// Require custom claims
256
JwtParser customClaimsParser = Jwts.parser()
257
.verifyWith(secretKey)
258
.require("role", "admin") // Require custom claim value
259
.require("tenant_id", "acme-corp") // Require tenant identification
260
.require("scope", "read:users") // Require specific scope
261
.require("version", 2) // Require numeric claim value
262
.build();
263
264
// Mixed requirements
265
JwtParser mixedParser = Jwts.parser()
266
.verifyWith(secretKey)
267
.requireIssuer("trusted-issuer")
268
.requireSubject("service-account")
269
.require("service_type", "background")
270
.require("priority", "high")
271
.clockSkewSeconds(60) // Also configure clock skew
272
.build();
273
274
// Parse with automatic validation
275
try {
276
Jws<Claims> validatedJws = requiredClaimsParser.parseSignedClaims(token);
277
// Token automatically validated against all requirements
278
Claims validatedClaims = validatedJws.getPayload();
279
processValidatedToken(validatedClaims);
280
281
} catch (MissingClaimException e) {
282
// Required claim is missing
283
handleMissingClaim(e.getClaimName());
284
} catch (IncorrectClaimException e) {
285
// Claim has incorrect value
286
handleIncorrectClaim(e.getClaimName(), e.getExpectedValue(), e.getActualValue());
287
}
288
```
289
290
### Algorithm Collection Configuration
291
292
Complete configuration of supported algorithms for parsing operations.
293
294
```java { .api }
295
import io.jsonwebtoken.security.MacAlgorithm;
296
import io.jsonwebtoken.security.SignatureAlgorithm;
297
import io.jsonwebtoken.security.AeadAlgorithm;
298
import io.jsonwebtoken.security.KeyAlgorithm;
299
import io.jsonwebtoken.io.CompressionAlgorithm;
300
301
// Configure signature algorithms collection
302
JwtParser signatureParser = Jwts.parser()
303
.verifyWith(secretKey)
304
.sig()
305
.add(Jwts.SIG.HS256) // Add specific MAC algorithm
306
.add(Jwts.SIG.HS384) // Add another MAC algorithm
307
.add(Jwts.SIG.RS256) // Add RSA signature algorithm
308
.remove(Jwts.SIG.NONE) // Remove unsecured algorithm
309
.and()
310
.build();
311
312
// Configure encryption algorithms collection
313
JwtParser encryptionParser = Jwts.parser()
314
.decryptWith(decryptionKey)
315
.enc()
316
.add(Jwts.ENC.A256GCM) // Add AEAD encryption algorithm
317
.add(Jwts.ENC.A192GCM) // Add another encryption algorithm
318
.and()
319
.key()
320
.add(Jwts.KEY.A256KW) // Add key wrapping algorithm
321
.add(Jwts.KEY.DIRECT) // Add direct key algorithm
322
.and()
323
.build();
324
325
// Configure compression algorithms collection
326
JwtParser compressionParser = Jwts.parser()
327
.verifyWith(secretKey)
328
.zip()
329
.add(Jwts.ZIP.DEF) // Add DEFLATE compression
330
.add(Jwts.ZIP.GZIP) // Add GZIP compression
331
.and()
332
.build();
333
334
// Comprehensive algorithm configuration
335
JwtParser comprehensiveParser = Jwts.parser()
336
.verifyWith(verificationKey)
337
.decryptWith(decryptionKey)
338
.sig()
339
.add(Jwts.SIG.HS512) // Strong HMAC
340
.add(Jwts.SIG.RS256) // RSA signature
341
.add(Jwts.SIG.ES256) // Elliptic curve signature
342
.and()
343
.enc()
344
.add(Jwts.ENC.A256GCM) // Strong encryption
345
.and()
346
.key()
347
.add(Jwts.KEY.A256KW) // Key wrapping
348
.add(Jwts.KEY.RSA_OAEP) // RSA key encryption
349
.and()
350
.zip()
351
.add(Jwts.ZIP.DEF) // Compression support
352
.and()
353
.clockSkewSeconds(30) // Time tolerance
354
.build();
355
```
356
357
### Unsecured JWT Handling
358
359
Configuration for handling unsecured JWTs in controlled scenarios.
360
361
```java { .api }
362
// Allow parsing of unsecured JWTs (use with extreme caution)
363
JwtParser unsecuredParser = Jwts.parser()
364
.unsecured() // Allow parsing without signature verification
365
.build();
366
367
// Parse unsecured JWT
368
Jwt<Header, Claims> unsecuredJwt = unsecuredParser.parseUnsecuredClaims(unsecuredToken);
369
Claims unsecuredClaims = unsecuredJwt.getPayload();
370
371
// Allow decompression of unsecured content (additional risk)
372
JwtParser unsecuredDecompressionParser = Jwts.parser()
373
.unsecured()
374
.unsecuredDecompression() // Allow decompression without verification
375
.build();
376
377
// Production pattern: Conditional unsecured parsing
378
public JwtParser createParser(boolean allowUnsecured, SecretKey key) {
379
JwtParserBuilder builder = Jwts.parser();
380
381
if (allowUnsecured) {
382
builder.unsecured();
383
// Log security warning
384
log.warn("SECURITY: Unsecured JWT parsing enabled");
385
} else {
386
builder.verifyWith(key);
387
}
388
389
return builder.build();
390
}
391
```
392
393
### Critical Header Parameters
394
395
```java { .api }
396
// Define critical header parameter handlers
397
JwtParser criticalParser = Jwts.parser()
398
.verifyWith(secretKey)
399
.critical() // Configure critical header handling
400
.add("custom-critical-param")
401
.add("security-level")
402
.and()
403
.build();
404
405
// Parser will validate that tokens include handlers for critical parameters
406
Jws<Claims> criticalJws = criticalParser.parseSignedClaims(tokenWithCriticalHeaders);
407
```
408
409
## Validation and Error Handling
410
411
### Time-based Validation
412
413
```java { .api }
414
import io.jsonwebtoken.ExpiredJwtException;
415
import io.jsonwebtoken.PrematureJwtException;
416
417
JwtParser timeParser = Jwts.parser()
418
.verifyWith(secretKey)
419
.clockSkewSeconds(30) // 30 seconds tolerance
420
.build();
421
422
try {
423
Jws<Claims> validJws = timeParser.parseSignedClaims(token);
424
Claims claims = validJws.getPayload();
425
426
// Token is valid and within time bounds
427
processValidToken(claims);
428
429
} catch (ExpiredJwtException e) {
430
// Token has expired
431
handleExpiredToken(e);
432
} catch (PrematureJwtException e) {
433
// Token is not yet valid (nbf claim)
434
handlePrematureToken(e);
435
}
436
```
437
438
### Signature Validation
439
440
```java { .api }
441
import io.jsonwebtoken.security.SignatureException;
442
import io.jsonwebtoken.MalformedJwtException;
443
444
try {
445
Jws<Claims> validJws = parser.parseSignedClaims(suspiciousToken);
446
447
} catch (SignatureException e) {
448
// Signature verification failed
449
logSecurityIncident("Invalid signature", e);
450
throw new SecurityException("Token signature invalid");
451
452
} catch (MalformedJwtException e) {
453
// Token structure is malformed
454
logSecurityIncident("Malformed token", e);
455
throw new IllegalArgumentException("Invalid token format");
456
}
457
```
458
459
### Encryption Validation
460
461
```java { .api }
462
import io.jsonwebtoken.security.SecurityException;
463
464
try {
465
Jwe<Claims> decryptedJwe = encryptParser.parseEncryptedClaims(encryptedToken);
466
467
} catch (SecurityException e) {
468
// Decryption failed or key mismatch
469
handleDecryptionFailure(e);
470
471
} catch (Exception e) {
472
// Other encryption-related errors
473
handleGeneralEncryptionError(e);
474
}
475
```
476
477
## Content Type Handling
478
479
### String Content
480
481
```java { .api }
482
// Parse JWT with string content
483
JwtParser contentParser = Jwts.parser()
484
.verifyWith(secretKey)
485
.build();
486
487
Jws<String> contentJws = contentParser.parseSignedContent(signedContentToken);
488
String content = contentJws.getPayload();
489
490
// Handle different content types based on header
491
String contentType = contentJws.getHeader().getContentType();
492
if ("application/json".equals(contentType)) {
493
JsonObject json = parseJson(content);
494
} else if ("text/plain".equals(contentType)) {
495
String plainText = content;
496
}
497
```
498
499
### Binary Content
500
501
```java { .api }
502
// Parse JWT with binary content
503
Jws<byte[]> binaryJws = contentParser.parseSignedContent(binaryContentToken);
504
byte[] binaryContent = binaryJws.getPayload();
505
506
// Process based on content type
507
String contentType = binaryJws.getHeader().getContentType();
508
if ("application/pdf".equals(contentType)) {
509
processPdfContent(binaryContent);
510
} else if ("image/jpeg".equals(contentType)) {
511
processImageContent(binaryContent);
512
}
513
```
514
515
## Multi-Key Scenarios
516
517
### Key Rotation Support
518
519
```java { .api }
520
import java.util.List;
521
522
// Support multiple verification keys for key rotation
523
List<SecretKey> rotationKeys = Arrays.asList(currentKey, previousKey, oldKey);
524
525
Locator<Key> rotationLocator = header -> {
526
String keyId = header.getKeyId();
527
528
// Try keys in order of preference
529
for (SecretKey key : rotationKeys) {
530
if (keyMatches(key, keyId)) {
531
return key;
532
}
533
}
534
535
throw new SecurityException("No valid key found for keyId: " + keyId);
536
};
537
538
JwtParser rotationParser = Jwts.parser()
539
.keyLocator(rotationLocator)
540
.build();
541
```
542
543
### Multi-Tenant Key Management
544
545
```java { .api }
546
// Tenant-specific key resolution
547
Locator<Key> tenantKeyLocator = header -> {
548
String keyId = header.getKeyId();
549
String tenantId = extractTenantFromKeyId(keyId);
550
551
return getTenantVerificationKey(tenantId, keyId);
552
};
553
554
JwtParser tenantParser = Jwts.parser()
555
.keyLocator(tenantKeyLocator)
556
.build();
557
558
// Parse tenant-specific tokens
559
Jws<Claims> tenantJws = tenantParser.parseSignedClaims(tenantToken);
560
String tenantId = tenantJws.getPayload().get("tenant_id", String.class);
561
```
562
563
## Provider and Serialization Configuration
564
565
### JCA Provider Configuration
566
567
```java { .api }
568
import java.security.Provider;
569
import org.bouncycastle.jce.provider.BouncyCastleProvider;
570
571
// Use specific JCA provider
572
Provider bcProvider = new BouncyCastleProvider();
573
574
JwtParser providerParser = Jwts.parser()
575
.provider(bcProvider)
576
.verifyWith(secretKey)
577
.build();
578
579
Jws<Claims> bcJws = providerParser.parseSignedClaims(token);
580
```
581
582
### JSON Deserialization
583
584
```java { .api }
585
import io.jsonwebtoken.io.Deserializer;
586
import io.jsonwebtoken.jackson.io.JacksonDeserializer;
587
588
// Custom JSON deserializer
589
Deserializer<Map<String, ?>> deserializer = new JacksonDeserializer<>();
590
591
JwtParser jsonParser = Jwts.parser()
592
.json(deserializer)
593
.verifyWith(secretKey)
594
.build();
595
596
Jws<Claims> customJws = jsonParser.parseSignedClaims(tokenWithCustomJson);
597
```
598
599
## Parsing Performance Optimization
600
601
### Parser Reuse
602
603
```java { .api }
604
// Create parser once and reuse (thread-safe)
605
JwtParser reusableParser = Jwts.parser()
606
.verifyWith(secretKey)
607
.clockSkewSeconds(30)
608
.build();
609
610
// Reuse across multiple parsing operations
611
public Claims parseUserToken(String token) {
612
return reusableParser.parseSignedClaims(token).getPayload();
613
}
614
615
public Claims parseServiceToken(String token) {
616
return reusableParser.parseSignedClaims(token).getPayload();
617
}
618
```
619
620
### Batch Processing
621
622
```java { .api }
623
// Process multiple tokens efficiently
624
List<String> tokens = getTokenBatch();
625
JwtParser batchParser = Jwts.parser()
626
.keyLocator(efficientKeyLocator)
627
.build();
628
629
List<Claims> claimsList = tokens.stream()
630
.map(token -> {
631
try {
632
return batchParser.parseSignedClaims(token).getPayload();
633
} catch (Exception e) {
634
logParsingError(token, e);
635
return null;
636
}
637
})
638
.filter(Objects::nonNull)
639
.collect(Collectors.toList());
640
```
641
642
## Unsecured JWT Handling
643
644
### Allowing Unsecured JWTs
645
646
```java { .api }
647
// Allow both secured and unsecured JWTs
648
JwtParser flexibleParser = Jwts.parser()
649
.unsecured() // Allow unsecured JWTs
650
.verifyWith(secretKey) // But verify if signature present
651
.build();
652
653
// Parse any type of JWT
654
Object result = flexibleParser.parse(unknownToken);
655
if (result instanceof Jws) {
656
Jws<Claims> jws = (Jws<Claims>) result;
657
Claims verifiedClaims = jws.getPayload();
658
} else if (result instanceof Jwt) {
659
Jwt<Claims> jwt = (Jwt<Claims>) result;
660
Claims unverifiedClaims = jwt.getPayload();
661
}
662
```
663
664
### Unsecured Decompression
665
666
```java { .api }
667
// Allow decompression for unsecured JWTs (use with caution)
668
JwtParser decompressParser = Jwts.parser()
669
.unsecured()
670
.unsecuredDecompression() // Allow decompression of unsecured JWTs
671
.build();
672
673
Jwt<Claims> decompressedJwt = decompressParser.parseClaimsJwt(compressedUnsecuredToken);
674
```
675
676
## Exception Handling
677
678
### JWT Exception Types
679
680
The JJWT library provides a comprehensive exception hierarchy for handling various JWT parsing and validation errors.
681
682
```java { .api }
683
import io.jsonwebtoken.JwtException;
684
import io.jsonwebtoken.MalformedJwtException;
685
import io.jsonwebtoken.ExpiredJwtException;
686
import io.jsonwebtoken.PrematureJwtException;
687
import io.jsonwebtoken.UnsupportedJwtException;
688
import io.jsonwebtoken.InvalidClaimException;
689
import io.jsonwebtoken.MissingClaimException;
690
import io.jsonwebtoken.IncorrectClaimException;
691
import io.jsonwebtoken.RequiredTypeException;
692
import io.jsonwebtoken.security.SecurityException;
693
import io.jsonwebtoken.security.SignatureException;
694
695
/**
696
* Base class for JWT-related runtime exceptions.
697
*/
698
public class JwtException extends RuntimeException;
699
700
/**
701
* Exception indicating that a JWT string is not in the proper three-part format.
702
*/
703
public class MalformedJwtException extends JwtException;
704
705
/**
706
* Exception indicating that a JWT is expired and therefore not valid.
707
*/
708
public class ExpiredJwtException extends ClaimJwtException;
709
710
/**
711
* Exception indicating that a JWT is not yet valid (nbf claim).
712
*/
713
public class PrematureJwtException extends ClaimJwtException;
714
715
/**
716
* Exception indicating an unsupported JWT type or algorithm.
717
*/
718
public class UnsupportedJwtException extends JwtException;
719
720
/**
721
* Exception indicating a claim validation failure.
722
*/
723
public class InvalidClaimException extends ClaimJwtException;
724
725
/**
726
* Exception indicating a required claim is missing.
727
*/
728
public class MissingClaimException extends InvalidClaimException;
729
730
/**
731
* Exception indicating a claim has an incorrect value.
732
*/
733
public class IncorrectClaimException extends InvalidClaimException;
734
735
/**
736
* Exception indicating incorrect type conversion.
737
*/
738
public class RequiredTypeException extends JwtException;
739
740
/**
741
* Base class for security-related exceptions.
742
*/
743
public class SecurityException extends JwtException;
744
745
/**
746
* Exception indicating JWT signature verification failure.
747
*/
748
public class SignatureException extends SecurityException;
749
```
750
751
### Exception Handling Patterns
752
753
```java { .api }
754
// Comprehensive error handling
755
public Claims parseAndValidateToken(String token, SecretKey key) {
756
JwtParser parser = Jwts.parser()
757
.verifyWith(key)
758
.build();
759
760
try {
761
Jws<Claims> jws = parser.parseSignedClaims(token);
762
return jws.getPayload();
763
764
} catch (ExpiredJwtException e) {
765
// Token has expired
766
Date expiration = e.getClaims().getExpiration();
767
throw new TokenExpiredException("Token expired at: " + expiration);
768
769
} catch (PrematureJwtException e) {
770
// Token not yet valid
771
Date notBefore = e.getClaims().getNotBefore();
772
throw new TokenNotYetValidException("Token not valid until: " + notBefore);
773
774
} catch (MalformedJwtException e) {
775
// Token format is invalid
776
throw new InvalidTokenFormatException("Invalid JWT format: " + e.getMessage());
777
778
} catch (SignatureException e) {
779
// Signature verification failed
780
throw new InvalidSignatureException("JWT signature verification failed");
781
782
} catch (MissingClaimException e) {
783
// Required claim is missing
784
String claimName = e.getClaimName();
785
throw new MissingRequiredClaimException("Missing required claim: " + claimName);
786
787
} catch (IncorrectClaimException e) {
788
// Claim has wrong value
789
String claimName = e.getClaimName();
790
Object expectedValue = e.getExpectedValue();
791
Object actualValue = e.getActualValue();
792
throw new InvalidClaimValueException(
793
"Claim '" + claimName + "' expected '" + expectedValue +
794
"' but was '" + actualValue + "'");
795
796
} catch (UnsupportedJwtException e) {
797
// Unsupported JWT type
798
throw new UnsupportedTokenException("Unsupported JWT: " + e.getMessage());
799
800
} catch (RequiredTypeException e) {
801
// Type conversion failed
802
throw new TypeConversionException("Failed to convert claim type: " + e.getMessage());
803
804
} catch (JwtException e) {
805
// General JWT error
806
throw new TokenProcessingException("JWT processing error: " + e.getMessage());
807
}
808
}
809
```
810
811
### Specific Exception Handling
812
813
```java { .api }
814
// Handle specific validation scenarios
815
public void handleExpirationWithGracePeriod(String token, SecretKey key) {
816
try {
817
JwtParser parser = Jwts.parser()
818
.verifyWith(key)
819
.clockSkewSeconds(30) // 30 second grace period
820
.build();
821
822
Jws<Claims> jws = parser.parseSignedClaims(token);
823
processValidToken(jws.getPayload());
824
825
} catch (ExpiredJwtException e) {
826
Claims expiredClaims = e.getClaims();
827
Date expiration = expiredClaims.getExpiration();
828
long gracePeriodMs = 60 * 1000; // 1 minute additional grace
829
830
if (System.currentTimeMillis() - expiration.getTime() < gracePeriodMs) {
831
// Within extended grace period
832
processValidToken(expiredClaims);
833
} else {
834
throw new TokenDefinitelyExpiredException("Token expired beyond grace period");
835
}
836
}
837
}
838
839
// Extract claims from expired tokens for logging
840
public void logTokenDetails(String token) {
841
try {
842
// This will throw ExpiredJwtException but still provide claims
843
Jwts.parser().verifyWith(key).build().parseSignedClaims(token);
844
845
} catch (ExpiredJwtException e) {
846
// Can still access claims from expired token
847
Claims claims = e.getClaims();
848
String subject = claims.getSubject();
849
Date expiration = claims.getExpiration();
850
851
log.info("Expired token - Subject: {}, Expired: {}", subject, expiration);
852
853
} catch (JwtException e) {
854
log.error("Token parsing failed: {}", e.getMessage());
855
}
856
}
857
```
858
859
### Custom Exception Handling
860
861
```java { .api }
862
// Custom exception handler for multi-tenant scenarios
863
public class TenantAwareJwtHandler {
864
865
public Claims parseToken(String token, String tenantId) {
866
try {
867
SecretKey tenantKey = getTenantKey(tenantId);
868
869
JwtParser parser = Jwts.parser()
870
.verifyWith(tenantKey)
871
.require("tenant_id", tenantId) // Require specific tenant
872
.build();
873
874
return parser.parseSignedClaims(token).getPayload();
875
876
} catch (IncorrectClaimException e) {
877
if ("tenant_id".equals(e.getClaimName())) {
878
throw new InvalidTenantException(
879
"Token belongs to different tenant: " + e.getActualValue());
880
}
881
throw e;
882
883
} catch (MissingClaimException e) {
884
if ("tenant_id".equals(e.getClaimName())) {
885
throw new InvalidTenantException("Token missing tenant claim");
886
}
887
throw e;
888
}
889
}
890
891
private SecretKey getTenantKey(String tenantId) {
892
// Retrieve tenant-specific key
893
return tenantKeyRepository.getKey(tenantId);
894
}
895
}
896
```
897
898
The JWT Parsing functionality provides comprehensive, secure, and flexible parsing capabilities with extensive validation options, error handling, and performance optimizations for production use cases.