JJWT Implementation module providing concrete implementations of JSON Web Token (JWT) creation, parsing, verification, and cryptographic operations for Java and Android applications.
—
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.
The Keys utility class provides secure key generation and management operations for JWT cryptographic operations.
import io.jsonwebtoken.security.Keys;
import io.jsonwebtoken.security.Password;
import io.jsonwebtoken.security.SecretKeyBuilder;
import io.jsonwebtoken.security.PrivateKeyBuilder;
import javax.crypto.SecretKey;
import java.security.KeyPair;
import java.security.PrivateKey;
import java.security.Provider;
/**
* Utility class for securely generating SecretKeys and KeyPairs.
*/
public final class Keys {
/**
* Creates a new SecretKey instance for use with HMAC-SHA algorithms based on the specified key byte array.
* @param bytes the key byte array
* @return a new SecretKey instance for use with HMAC-SHA algorithms
* @throws WeakKeyException if the key byte array length is less than 256 bits (32 bytes)
*/
public static SecretKey hmacShaKeyFor(byte[] bytes) throws WeakKeyException;
/**
* Returns a new Password instance suitable for use with password-based key derivation algorithms.
* @param password the raw password character array to clone
* @return a new Password instance that wraps a new clone of the specified password character array
*/
public static Password password(char[] password);
/**
* Returns a SecretKeyBuilder that produces the specified key, allowing association with a Provider.
* @param key the secret key to use for cryptographic operations
* @return a new SecretKeyBuilder that produces the specified key
*/
public static SecretKeyBuilder builder(SecretKey key);
/**
* Returns a PrivateKeyBuilder that produces the specified key, allowing association with a PublicKey or Provider.
* @param key the private key to use for cryptographic operations
* @return a new PrivateKeyBuilder that produces the specified private key
*/
public static PrivateKeyBuilder builder(PrivateKey key);
}// Create HMAC key from byte array
byte[] keyBytes = generateSecureRandomBytes(32); // 256 bits for HS256
SecretKey hmacKey = Keys.hmacShaKeyFor(keyBytes);
// Key strength validation - automatically selects appropriate HMAC algorithm
byte[] strongKeyBytes = generateSecureRandomBytes(64); // 512 bits
SecretKey strongKey = Keys.hmacShaKeyFor(strongKeyBytes); // Returns HmacSHA512
// Weak key handling
try {
byte[] weakKeyBytes = generateSecureRandomBytes(16); // Only 128 bits
SecretKey weakKey = Keys.hmacShaKeyFor(weakKeyBytes);
} catch (WeakKeyException e) {
// Handle insufficient key strength
System.err.println("Key too weak: " + e.getMessage());
// Use algorithm-specific key generation instead
SecretKey safeKey = Jwts.SIG.HS256.key().build();
}// Create password for PBKDF2 operations
char[] passwordChars = "secure-password".toCharArray();
Password password = Keys.password(passwordChars);
// Use with password-based algorithms
SecretKey derivedKey = Jwts.KEY.PBES2_HS256_A128KW.key()
.password(password)
.build();
// Clear password after use for security
Arrays.fill(passwordChars, '\0');
password.destroy(); // Clear internal password copy// Associate secret key with specific JCA provider
Provider hsm = Security.getProvider("SunPKCS11-HSM");
SecretKey hsmKey = getKeyFromHSM(); // Hypothetical HSM key
SecretKey providerKey = Keys.builder(hsmKey)
.provider(hsm)
.build();
// Associate private key with public key and provider
PrivateKey privateKey = getPrivateKeyFromHSM();
PublicKey publicKey = getCorrespondingPublicKey();
PrivateKey enhancedPrivateKey = Keys.builder(privateKey)
.publicKey(publicKey)
.provider(hsm)
.build();
// Use in JWT operations
String jwt = Jwts.builder()
.subject("user")
.signWith(enhancedPrivateKey)
.compact();// Recommended approach: Use algorithm-specific key generation
// Instead of Keys.secretKeyFor(SignatureAlgorithm.HS256) [deprecated]
SecretKey hs256Key = Jwts.SIG.HS256.key().build();
SecretKey hs384Key = Jwts.SIG.HS384.key().build();
SecretKey hs512Key = Jwts.SIG.HS512.key().build();
// Instead of Keys.keyPairFor(SignatureAlgorithm.RS256) [deprecated]
KeyPair rs256KeyPair = Jwts.SIG.RS256.keyPair().build();
KeyPair ecKeyPair = Jwts.SIG.ES256.keyPair().build();
KeyPair eddsaKeyPair = Jwts.SIG.EdDSA.keyPair().build();
// With custom provider and secure random
Provider customProvider = getCustomProvider();
SecureRandom secureRandom = getSecureRandom();
SecretKey customKey = Jwts.SIG.HS256.key()
.provider(customProvider)
.random(secureRandom)
.build();RFC 4648 compliant Base64URL encoding and decoding without padding.
import io.jsonwebtoken.impl.Base64UrlCodec;
import java.nio.charset.StandardCharsets;
// Create codec instance
Base64UrlCodec codec = new Base64UrlCodec();
// Encode string to Base64URL
String text = "Hello, World!";
String encoded = codec.encode(text);
// Result: "SGVsbG8sIFdvcmxkIQ" (no padding)
// Encode byte array to Base64URL
byte[] data = "Binary data".getBytes(StandardCharsets.UTF_8);
String encodedBytes = codec.encode(data);
// Decode Base64URL to string
String decoded = codec.decodeToString(encoded);
// Result: "Hello, World!"
// Decode Base64URL to byte array
byte[] decodedBytes = codec.decode(encodedBytes);
String recovered = new String(decodedBytes, StandardCharsets.UTF_8);// Demonstrate Base64URL differences
String testData = "Test data with special characters: +/=";
byte[] bytes = testData.getBytes(StandardCharsets.UTF_8);
// Standard Base64 (with padding and +/= characters)
String standardB64 = Base64.getEncoder().encodeToString(bytes);
// Contains: +, /, = characters
// Base64URL (no padding, URL-safe characters)
Base64UrlCodec urlCodec = new Base64UrlCodec();
String base64Url = urlCodec.encode(bytes);
// Uses: -, _ instead of +, / and no padding
// URL safety demonstration
String urlWithStandardB64 = "https://api.example.com/token?jwt=" + standardB64;
// Problematic: contains +/= that need URL encoding
String urlWithBase64Url = "https://api.example.com/token?jwt=" + base64Url;
// Safe: no characters requiring URL encoding// Handle different input types
Base64UrlCodec codec = new Base64UrlCodec();
// Encode various data types
String jsonData = "{\"sub\":\"user\",\"exp\":1234567890}";
String encodedJson = codec.encode(jsonData);
byte[] binaryData = {0x48, 0x65, 0x6C, 0x6C, 0x6F}; // "Hello" in bytes
String encodedBinary = codec.encode(binaryData);
// Large data handling
byte[] largeData = generateLargeByteArray(10000);
String encodedLarge = codec.encode(largeData);
byte[] decodedLarge = codec.decode(encodedLarge);
// Verify round-trip integrity
boolean integrityCheck = Arrays.equals(largeData, decodedLarge);
// Error handling
try {
String invalidBase64Url = "Invalid!!!Base64URL";
byte[] result = codec.decode(invalidBase64Url);
} catch (IllegalArgumentException e) {
// Handle invalid Base64URL input
log.error("Invalid Base64URL input", e);
}Memory-efficient stream operations for handling large payloads.
import io.jsonwebtoken.impl.io.Streams;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
// Copy streams efficiently
InputStream source = new FileInputStream("large-file.json");
OutputStream destination = new ByteArrayOutputStream();
// Copy with automatic resource management
long bytesCopied = Streams.copy(source, destination);
// Convert stream to byte array
InputStream dataStream = new ByteArrayInputStream("Stream data".getBytes());
byte[] streamBytes = Streams.bytes(dataStream);
// Handle large streams without loading everything into memory
InputStream largeStream = new FileInputStream("very-large-file.dat");
OutputStream output = new FileOutputStream("output-file.dat");
Streams.copy(largeStream, output);// Create JWT from large stream content
InputStream largePayload = new FileInputStream("large-document.json");
String streamJwt = Jwts.builder()
.content(largePayload) // Stream directly without loading into memory
.header()
.contentType("application/json")
.and()
.signWith(secretKey)
.compact();
// Parse JWT with stream content
JwtParser parser = Jwts.parser()
.verifyWith(secretKey)
.build();
Jws<InputStream> streamJws = parser.parseSignedContent(streamJwt);
InputStream contentStream = streamJws.getPayload();
// Process stream content efficiently
try (InputStream content = contentStream) {
byte[] data = Streams.bytes(content);
processLargeData(data);
}// Process large JWT content without memory issues
public static void processLargeJwtContent(String jwt, SecretKey key) {
JwtParser parser = Jwts.parser()
.verifyWith(key)
.build();
// Parse to stream to avoid loading entire payload
Jws<InputStream> jws = parser.parseSignedContent(jwt);
try (InputStream content = jws.getPayload()) {
// Process in chunks to manage memory
byte[] buffer = new byte[8192]; // 8KB buffer
int bytesRead;
while ((bytesRead = content.read(buffer)) != -1) {
processChunk(buffer, bytesRead);
}
} catch (IOException e) {
throw new RuntimeException("Failed to process JWT content", e);
}
}
private static void processChunk(byte[] buffer, int length) {
// Process data chunk without storing entire payload
String chunk = new String(buffer, 0, length, StandardCharsets.UTF_8);
// ... process chunk
}Service loader utility for implementation discovery and plugin architecture.
import io.jsonwebtoken.impl.lang.Services;
import io.jsonwebtoken.io.Serializer;
import io.jsonwebtoken.io.Deserializer;
import io.jsonwebtoken.security.SecureDigestAlgorithm;
import java.util.Iterator;
import java.util.function.Predicate;
// Get first available service implementation
Serializer<Map<String, ?>> serializer = Services.get(Serializer.class);
// Get service with specific criteria
Predicate<Deserializer<Map<String, ?>>> jsonFilter =
deserializer -> deserializer.getClass().getSimpleName().contains("Jackson");
Deserializer<Map<String, ?>> jsonDeserializer =
Services.get(Deserializer.class, jsonFilter);
// Get all service implementations
Iterator<SecureDigestAlgorithm> algorithms =
Services.iterator(SecureDigestAlgorithm.class);
// Service availability check
boolean hasJacksonSupport = Services.get(Serializer.class) != null;// Load custom algorithm implementations
public static void loadCustomAlgorithms() {
// Service loader automatically discovers implementations
Iterator<SecureDigestAlgorithm> customAlgorithms =
Services.iterator(SecureDigestAlgorithm.class);
while (customAlgorithms.hasNext()) {
SecureDigestAlgorithm algorithm = customAlgorithms.next();
if (algorithm.getId().startsWith("CUSTOM_")) {
// Register custom algorithm
registerCustomAlgorithm(algorithm);
}
}
}
// Load serialization providers
public static Serializer<Map<String, ?>> loadBestSerializer() {
// Try Jackson first
Serializer<Map<String, ?>> jacksonSerializer =
Services.get(Serializer.class, s ->
s.getClass().getName().contains("jackson"));
if (jacksonSerializer != null) {
return jacksonSerializer;
}
// Fallback to any available serializer
return Services.get(Serializer.class);
}
// Service caching and reload
Services.reload(); // Clear service cache and reloadGeneric registry implementation for algorithm and component collections.
import io.jsonwebtoken.impl.lang.DefaultRegistry;
import io.jsonwebtoken.security.SecureDigestAlgorithm;
import io.jsonwebtoken.CompressionAlgorithm;
// Create custom algorithm registry
DefaultRegistry<SecureDigestAlgorithm<?, ?>> customSigRegistry =
new DefaultRegistry<>("Custom Signature Algorithms");
// Add algorithms to registry
SecureDigestAlgorithm<?, ?> customAlgorithm = createCustomAlgorithm();
customSigRegistry.add(customAlgorithm);
// Registry operations
boolean hasAlgorithm = customSigRegistry.containsKey("CUSTOM_HS256");
SecureDigestAlgorithm<?, ?> algorithm = customSigRegistry.get("CUSTOM_HS256");
Set<String> algorithmIds = customSigRegistry.keySet();
Collection<SecureDigestAlgorithm<?, ?>> allAlgorithms = customSigRegistry.values();
// Registry with validation
SecureDigestAlgorithm<?, ?> validatedAlgorithm =
customSigRegistry.forKey("CUSTOM_HS256"); // Throws if not found// Extend existing registries
public class ExtendedSignatureRegistry extends DefaultRegistry<SecureDigestAlgorithm<?, ?>> {
public ExtendedSignatureRegistry() {
super("Extended Signature Algorithms");
// Add all standard algorithms
addAll(Jwts.SIG.get().values());
// Add custom algorithms
add(new CustomHMACAlgorithm("CUSTOM_HS256", 256));
add(new CustomRSAAlgorithm("CUSTOM_RS256"));
add(new CustomECAlgorithm("CUSTOM_ES256"));
}
}
// Use extended registry
ExtendedSignatureRegistry extendedSig = new ExtendedSignatureRegistry();
JwtParser extendedParser = Jwts.parser()
.verifyWith(secretKey)
.sig()
.add(extendedSig.get("CUSTOM_HS256"))
.and()
.build();Type-safe parameter validation and assertion utilities.
import io.jsonwebtoken.impl.lang.Parameters;
// Parameter validation examples
public static SecretKey validateSecretKey(SecretKey key, String algorithmId) {
// Check for null
Parameters.notNull(key, "Secret key cannot be null");
// Check key algorithm
String keyAlgorithm = key.getAlgorithm();
Parameters.notEmpty(keyAlgorithm, "Key algorithm cannot be empty");
// Validate key length
byte[] encoded = key.getEncoded();
Parameters.notEmpty(encoded, "Key must be encodable");
int bitLength = encoded.length * 8;
Parameters.gt(bitLength, 255, "Key must be at least 256 bits");
return key;
}
// String parameter validation
public static String validateKeyId(String keyId) {
Parameters.notEmpty(keyId, "Key ID cannot be null or empty");
Parameters.maxLength(keyId, 255, "Key ID too long");
// Custom validation
if (!keyId.matches("^[a-zA-Z0-9_-]+$")) {
throw new IllegalArgumentException("Invalid key ID format");
}
return keyId;
}
// Collection validation
public static <T> List<T> validateList(List<T> list, String paramName) {
Parameters.notNull(list, paramName + " cannot be null");
Parameters.notEmpty(list, paramName + " cannot be empty");
// Validate elements
for (int i = 0; i < list.size(); i++) {
Parameters.notNull(list.get(i), paramName + "[" + i + "] cannot be null");
}
return list;
}// Complex parameter validation patterns
public static KeyPair validateKeyPairForAlgorithm(KeyPair keyPair, String algorithm) {
Parameters.notNull(keyPair, "KeyPair cannot be null");
Parameters.notNull(keyPair.getPublic(), "Public key cannot be null");
Parameters.notNull(keyPair.getPrivate(), "Private key cannot be null");
// Algorithm-specific validation
if (algorithm.startsWith("RS") || algorithm.startsWith("PS")) {
// RSA validation
Parameters.eq(keyPair.getPublic().getAlgorithm(), "RSA",
"Algorithm " + algorithm + " requires RSA keys");
// Check key size
RSAPublicKey rsaPublic = (RSAPublicKey) keyPair.getPublic();
int keySize = rsaPublic.getModulus().bitLength();
Parameters.gte(keySize, 2048, "RSA keys must be at least 2048 bits");
} else if (algorithm.startsWith("ES")) {
// EC validation
Parameters.eq(keyPair.getPublic().getAlgorithm(), "EC",
"Algorithm " + algorithm + " requires EC keys");
}
return keyPair;
}
// Conditional validation
public static void validateJWEParameters(Key kek, String keyAlg, String encAlg) {
Parameters.notNull(kek, "Key encryption key cannot be null");
Parameters.notEmpty(keyAlg, "Key algorithm cannot be empty");
Parameters.notEmpty(encAlg, "Encryption algorithm cannot be empty");
// Validate key compatibility with algorithm
if (keyAlg.startsWith("RSA")) {
Parameters.isTrue(kek instanceof PublicKey || kek instanceof PrivateKey,
"RSA algorithms require asymmetric keys");
} else if (keyAlg.contains("KW")) {
Parameters.isTrue(kek instanceof SecretKey,
"Key wrap algorithms require symmetric keys");
}
}Common functional utilities and constants.
import io.jsonwebtoken.impl.lang.Functions;
import java.util.function.Function;
import java.util.function.Predicate;
// Common function constants and utilities
// (Specific implementations depend on the Functions class content)
// Example usage patterns for functional operations
public static <T> List<T> filterAndTransform(List<T> input,
Predicate<T> filter,
Function<T, T> transformer) {
return input.stream()
.filter(filter)
.map(transformer)
.collect(Collectors.toList());
}
// Functional JWT processing
public static List<Claims> extractClaimsFromTokens(List<String> tokens,
SecretKey key) {
JwtParser parser = Jwts.parser().verifyWith(key).build();
return tokens.stream()
.map(token -> {
try {
return parser.parseSignedClaims(token).getPayload();
} catch (Exception e) {
return null; // Filter out invalid tokens
}
})
.filter(Objects::nonNull)
.collect(Collectors.toList());
}Testing utility for fixed-time scenarios.
import io.jsonwebtoken.impl.FixedClock;
import io.jsonwebtoken.Clock;
import java.time.Instant;
import java.util.Date;
// Create fixed clock for testing
Date fixedTime = Date.from(Instant.parse("2024-01-01T12:00:00Z"));
Clock fixedClock = new FixedClock(fixedTime);
// Use fixed clock in JWT operations
JwtParser testParser = Jwts.parser()
.verifyWith(secretKey)
.clock(fixedClock) // All time-based validations use fixed time
.build();
// Create JWT with fixed issuedAt
String testJwt = Jwts.builder()
.subject("test-user")
.issuedAt(fixedClock.now()) // Uses fixed time
.expiration(new Date(fixedTime.getTime() + 3600000)) // 1 hour later
.signWith(secretKey)
.compact();
// Test time-based scenarios
public static void testTokenExpiration() {
Date now = Date.from(Instant.parse("2024-01-01T12:00:00Z"));
Date expiry = Date.from(Instant.parse("2024-01-01T13:00:00Z"));
// Create token
Clock createTime = new FixedClock(now);
String jwt = Jwts.builder()
.subject("user")
.issuedAt(createTime.now())
.expiration(expiry)
.signWith(secretKey)
.compact();
// Test parsing at different times
Clock beforeExpiry = new FixedClock(Date.from(Instant.parse("2024-01-01T12:30:00Z")));
Clock afterExpiry = new FixedClock(Date.from(Instant.parse("2024-01-01T14:00:00Z")));
// Should succeed
JwtParser validParser = Jwts.parser()
.verifyWith(secretKey)
.clock(beforeExpiry)
.build();
Claims validClaims = validParser.parseSignedClaims(jwt).getPayload();
// Should fail with ExpiredJwtException
JwtParser expiredParser = Jwts.parser()
.verifyWith(secretKey)
.clock(afterExpiry)
.build();
try {
expiredParser.parseSignedClaims(jwt);
fail("Should have thrown ExpiredJwtException");
} catch (ExpiredJwtException e) {
// Expected
}
}// Reusable component caching
public class JWTUtilityCache {
private static final Base64UrlCodec CODEC = new Base64UrlCodec();
private static final Map<String, JwtParser> PARSER_CACHE = new ConcurrentHashMap<>();
public static String encodePayload(Object payload) {
String json = serializeToJson(payload);
return CODEC.encode(json);
}
public static JwtParser getCachedParser(String keyId, Key key) {
return PARSER_CACHE.computeIfAbsent(keyId, k ->
Jwts.parser().verifyWith(key).build()
);
}
public static void clearCache() {
PARSER_CACHE.clear();
}
}
// Batch processing utilities
public static Map<String, Claims> parseTokenBatch(List<String> tokens,
Map<String, Key> keyMap) {
return tokens.parallelStream()
.collect(Collectors.toConcurrentMap(
token -> token, // Use token as key
token -> {
try {
// Extract key ID from header
String keyId = extractKeyIdFromToken(token);
Key key = keyMap.get(keyId);
if (key != null) {
JwtParser parser = JWTUtilityCache.getCachedParser(keyId, key);
return parser.parseSignedClaims(token).getPayload();
}
return null;
} catch (Exception e) {
return null; // Skip invalid tokens
}
},
(existing, replacement) -> existing, // Keep first valid result
ConcurrentHashMap::new
)).entrySet().stream()
.filter(entry -> entry.getValue() != null)
.collect(Collectors.toMap(
Map.Entry::getKey,
Map.Entry::getValue
));
}The IO package provides interfaces and utilities for encoding, decoding, serialization, and deserialization operations used throughout JJWT.
import io.jsonwebtoken.io.Encoder;
import io.jsonwebtoken.io.Decoder;
import io.jsonwebtoken.io.Serializer;
import io.jsonwebtoken.io.Deserializer;
import io.jsonwebtoken.io.Parser;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Map;
/**
* An encoder converts data of one type into another formatted data value.
*/
public interface Encoder<T, R> {
/**
* Convert the specified data into another formatted data value.
* @param t the data to convert
* @return the converted data
*/
R encode(T t);
}
/**
* A decoder converts formatted data of one type into another data type.
*/
public interface Decoder<T, R> {
/**
* Convert the specified formatted data into another data value.
* @param t the formatted data to convert
* @return the converted data
*/
R decode(T t);
}
/**
* A Serializer is able to convert a Java object into a formatted byte stream.
*/
public interface Serializer<T> {
/**
* Converts the specified Java object into a formatted data byte array.
* @param t the Java object to convert
* @return the formatted data as a byte array
*/
byte[] serialize(T t);
/**
* Converts the specified Java object into a formatted data stream.
* @param t the Java object to convert
* @param out the OutputStream to write to
*/
void serialize(T t, OutputStream out);
}
/**
* A Deserializer is able to convert formatted byte data back into a Java object.
*/
public interface Deserializer<T> {
/**
* Convert the specified formatted data byte array into a Java object.
* @param data the formatted data bytes
* @return the reconstituted Java object
*/
T deserialize(byte[] data);
/**
* Convert the specified formatted data stream into a Java object.
* @param in the InputStream to read from
* @return the reconstituted Java object
*/
T deserialize(InputStream in);
}
/**
* A Parser converts data from one format to another.
*/
public interface Parser<T> {
/**
* Parse the specified value into the expected Java object.
* @param value the formatted value to parse
* @return the parsed Java object
*/
T parse(CharSequence value);
}import io.jsonwebtoken.io.Encoders;
import io.jsonwebtoken.io.Decoders;
import io.jsonwebtoken.io.Base64Encoder;
import io.jsonwebtoken.io.Base64Decoder;
// Standard Base64 encoding/decoding
Base64Encoder base64Encoder = Encoders.BASE64;
Base64Decoder base64Decoder = Decoders.BASE64;
String originalData = "Hello, World!";
String encoded = base64Encoder.encode(originalData);
String decoded = base64Decoder.decode(encoded);
// Base64URL encoding/decoding (JWT standard)
Base64Encoder base64UrlEncoder = Encoders.BASE64URL;
Base64Decoder base64UrlDecoder = Decoders.BASE64URL;
String urlSafeEncoded = base64UrlEncoder.encode(originalData);
String urlSafeDecoded = base64UrlDecoder.decode(urlSafeEncoded);
// Binary data encoding
byte[] binaryData = "Binary content".getBytes(StandardCharsets.UTF_8);
String encodedBinary = base64UrlEncoder.encode(binaryData);
byte[] decodedBinary = base64UrlDecoder.decodeToBytes(encodedBinary);// Use with JWT builder for custom JSON serialization
Map<String, Object> customPayload = new HashMap<>();
customPayload.put("user_id", 12345);
customPayload.put("roles", Arrays.asList("admin", "user"));
customPayload.put("metadata", Map.of("department", "engineering"));
Serializer<Map<String, ?>> jsonSerializer = getJsonSerializer();
String jwt = Jwts.builder()
.claims(customPayload)
.json(jsonSerializer) // Use custom JSON serializer
.signWith(secretKey)
.compact();
// Use with JWT parser for custom JSON deserialization
Deserializer<Map<String, ?>> jsonDeserializer = getJsonDeserializer();
JwtParser parser = Jwts.parser()
.verifyWith(secretKey)
.json(jsonDeserializer) // Use custom JSON deserializer
.build();
Jws<Claims> jws = parser.parseSignedClaims(jwt);// Custom serializer for large payloads
public class StreamingJsonSerializer implements Serializer<Map<String, ?>> {
@Override
public byte[] serialize(Map<String, ?> map) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
serialize(map, baos);
return baos.toByteArray();
}
@Override
public void serialize(Map<String, ?> map, OutputStream out) {
try (JsonGenerator generator = createJsonGenerator(out)) {
generator.writeStartObject();
for (Map.Entry<String, ?> entry : map.entrySet()) {
generator.writeObjectField(entry.getKey(), entry.getValue());
}
generator.writeEndObject();
} catch (IOException e) {
throw new SerializationException("JSON serialization failed", e);
}
}
}
// Custom deserializer for streaming
public class StreamingJsonDeserializer implements Deserializer<Map<String, ?>> {
@Override
public Map<String, ?> deserialize(byte[] data) {
return deserialize(new ByteArrayInputStream(data));
}
@Override
public Map<String, ?> deserialize(InputStream in) {
try (JsonParser parser = createJsonParser(in)) {
return parseJsonObject(parser);
} catch (IOException e) {
throw new DeserializationException("JSON deserialization failed", e);
}
}
}import io.jsonwebtoken.io.IOException;
import io.jsonwebtoken.io.SerializationException;
import io.jsonwebtoken.io.DeserializationException;
import io.jsonwebtoken.io.DecodingException;
/**
* Base IO exception for all input/output related errors.
*/
public class IOException extends RuntimeException;
/**
* Exception thrown when object serialization fails.
*/
public class SerializationException extends IOException;
/**
* Exception thrown when data deserialization fails.
*/
public class DeserializationException extends IOException;
/**
* Exception thrown when data decoding fails.
*/
public class DecodingException extends IOException;
// Exception handling in custom serializers
public class SafeJsonSerializer implements Serializer<Map<String, ?>> {
@Override
public byte[] serialize(Map<String, ?> map) {
try {
return performSerialization(map);
} catch (Exception e) {
throw new SerializationException("Failed to serialize JSON: " + e.getMessage(), e);
}
}
@Override
public void serialize(Map<String, ?> map, OutputStream out) {
try {
performStreamSerialization(map, out);
} catch (Exception e) {
throw new SerializationException("Failed to serialize JSON to stream: " + e.getMessage(), e);
}
}
}// Custom parser for special JWT formats
public class CustomJwtFormatParser implements Parser<Jwt<?, ?>> {
private final JwtParser delegate;
public CustomJwtFormatParser(JwtParser delegate) {
this.delegate = delegate;
}
@Override
public Jwt<?, ?> parse(CharSequence value) {
// Pre-process custom format
String standardJwt = convertCustomFormatToStandard(value.toString());
// Delegate to standard parser
return delegate.parse(standardJwt);
}
private String convertCustomFormatToStandard(String customFormat) {
// Implementation-specific conversion logic
if (customFormat.startsWith("CUSTOM:")) {
return customFormat.substring(7); // Remove custom prefix
}
return customFormat;
}
}
// Usage with custom parser
Parser<Jwt<?, ?>> customParser = new CustomJwtFormatParser(
Jwts.parser()
.verifyWith(secretKey)
.build()
);
Jwt<?, ?> jwt = customParser.parse("CUSTOM:eyJ0eXAiOiJKV1QiLCJhbGc...");import io.jsonwebtoken.Clock;
import io.jsonwebtoken.Locator;
import io.jsonwebtoken.Identifiable;
import io.jsonwebtoken.security.SecretKeyBuilder;
import io.jsonwebtoken.security.PrivateKeyBuilder;
import io.jsonwebtoken.security.Password;
import java.util.Date;
import java.security.Key;
/**
* Clock interface for time operations.
*/
public interface Clock {
/**
* Returns the current time as a Date.
* @return the current time
*/
Date now();
}
/**
* Locator interface for resource location operations.
*/
public interface Locator<T> {
/**
* Locates a resource based on the provided context.
* @param header JWT header providing context
* @return the located resource
*/
T locate(JwsHeader header);
}
/**
* Identifiable interface for objects with string identifiers.
*/
public interface Identifiable {
/**
* Returns the string identifier of this object.
* @return the string identifier
*/
String getId();
}
/**
* Builder for SecretKey instances with provider support.
*/
public interface SecretKeyBuilder extends Builder<SecretKey> {
/**
* Associates a Provider that must be used with the key.
* @param provider the JCA Provider
* @return this builder for method chaining
*/
SecretKeyBuilder provider(Provider provider);
}
/**
* Builder for PrivateKey instances with public key and provider support.
*/
public interface PrivateKeyBuilder extends Builder<PrivateKey> {
/**
* Associates a public key with the private key.
* @param publicKey the corresponding public key
* @return this builder for method chaining
*/
PrivateKeyBuilder publicKey(PublicKey publicKey);
/**
* Associates a Provider that must be used with the key.
* @param provider the JCA Provider
* @return this builder for method chaining
*/
PrivateKeyBuilder provider(Provider provider);
}
/**
* Password interface for password-based key derivation.
*/
public interface Password extends Key {
/**
* Returns the password as a character array.
* @return the password characters
*/
char[] toCharArray();
/**
* Destroys this password by clearing its internal state.
*/
void destroy();
}import io.jsonwebtoken.JwtVisitor;
import io.jsonwebtoken.SupportedJwtVisitor;
/**
* Visitor interface for processing different JWT types.
*/
public interface JwtVisitor<T> {
/**
* Visit an unsecured JWT with content payload.
* @param jwt the unsecured content JWT
* @return visitor result
*/
T visit(Jwt<Header, byte[]> jwt);
/**
* Visit an unsecured JWT with claims payload.
* @param jwt the unsecured claims JWT
* @return visitor result
*/
T visit(Jwt<Header, Claims> jwt);
/**
* Visit a signed JWT with content payload.
* @param jws the signed content JWT
* @return visitor result
*/
T visit(Jws<byte[]> jws);
/**
* Visit a signed JWT with claims payload.
* @param jws the signed claims JWT
* @return visitor result
*/
T visit(Jws<Claims> jws);
/**
* Visit an encrypted JWT with content payload.
* @param jwe the encrypted content JWT
* @return visitor result
*/
T visit(Jwe<byte[]> jwe);
/**
* Visit an encrypted JWT with claims payload.
* @param jwe the encrypted claims JWT
* @return visitor result
*/
T visit(Jwe<Claims> jwe);
}
/**
* Base visitor implementation with default unsupported operation responses.
*/
public abstract class SupportedJwtVisitor<T> implements JwtVisitor<T> {
/**
* Default message for unsupported operations.
*/
public static final String UNSUPPORTED_MSG = "Unsupported JWT type.";
@Override
public T visit(Jwt<Header, byte[]> jwt) {
throw new UnsupportedJwtException(UNSUPPORTED_MSG);
}
@Override
public T visit(Jwt<Header, Claims> jwt) {
throw new UnsupportedJwtException(UNSUPPORTED_MSG);
}
@Override
public T visit(Jws<byte[]> jws) {
throw new UnsupportedJwtException(UNSUPPORTED_MSG);
}
@Override
public T visit(Jws<Claims> jws) {
throw new UnsupportedJwtException(UNSUPPORTED_MSG);
}
@Override
public T visit(Jwe<byte[]> jwe) {
throw new UnsupportedJwtException(UNSUPPORTED_MSG);
}
@Override
public T visit(Jwe<Claims> jwe) {
throw new UnsupportedJwtException(UNSUPPORTED_MSG);
}
}
// Example visitor implementation
public class JwtTypeExtractor extends SupportedJwtVisitor<String> {
@Override
public String visit(Jwt<Header, Claims> jwt) {
return "unsecured-claims";
}
@Override
public String visit(Jws<Claims> jws) {
return "signed-claims";
}
@Override
public String visit(Jwe<Claims> jwe) {
return "encrypted-claims";
}
}
// Usage with visitor pattern
JwtTypeExtractor extractor = new JwtTypeExtractor();
Jwt<?, ?> someJwt = parser.parse(token);
String jwtType = someJwt.accept(extractor);import io.jsonwebtoken.lang.Registry;
import io.jsonwebtoken.lang.NestedCollection;
/**
* Registry interface for algorithm and component lookup.
*/
public interface Registry<K, V> extends Map<K, V> {
/**
* Returns the value associated with the specified key.
* @param key the key to look up
* @return the associated value
*/
V forKey(K key);
/**
* Returns all values in the registry.
* @return collection of all values
*/
Collection<V> values();
}
/**
* Nested collection interface for fluent configuration.
*/
public interface NestedCollection<T, P> {
/**
* Add an item to the collection.
* @param item the item to add
* @return this collection for chaining
*/
NestedCollection<T, P> add(T item);
/**
* Remove an item from the collection.
* @param item the item to remove
* @return this collection for chaining
*/
NestedCollection<T, P> remove(T item);
/**
* Return to the parent builder.
* @return the parent builder
*/
P and();
}The Utilities implementation provides robust, performance-optimized supporting functionality that enables the core JWT operations while maintaining extensibility and proper error handling.
Install with Tessl CLI
npx tessl i tessl/maven-io-jsonwebtoken--jjwt-impl