JJWT API - JSON Web Token library API for Java and Android
—
This document covers encoding, decoding, and serialization utilities in JJWT API for Base64/Base64URL operations and custom JSON processing.
JJWT provides standard encoders and decoders for Base64 and Base64URL operations, which are essential for JWT processing.
public final class Encoders {
public static final Encoder<byte[], String> BASE64;
public static final Encoder<byte[], String> BASE64URL;
}public final class Decoders {
public static final Decoder<CharSequence, byte[]> BASE64;
public static final Decoder<CharSequence, byte[]> BASE64URL;
}public interface Encoder<T, R> {
R encode(T t) throws EncodingException;
}
public interface Decoder<T, R> {
R decode(T t) throws DecodingException;
}import io.jsonwebtoken.io.Encoders;
import io.jsonwebtoken.io.Decoders;
// Encode bytes to Base64URL string (JWT standard)
byte[] data = "Hello, World!".getBytes(StandardCharsets.UTF_8);
String base64url = Encoders.BASE64URL.encode(data);
System.out.println(base64url); // SGVsbG8sIFdvcmxkIQ
// Decode Base64URL string back to bytes
byte[] decoded = Decoders.BASE64URL.decode(base64url);
String original = new String(decoded, StandardCharsets.UTF_8);
System.out.println(original); // Hello, World!
// Standard Base64 encoding (with padding)
String base64 = Encoders.BASE64.encode(data);
System.out.println(base64); // SGVsbG8sIFdvcmxkIQ==
// Decode standard Base64
byte[] decodedBase64 = Decoders.BASE64.decode(base64);JJWT provides interfaces for custom JSON serialization and deserialization, allowing integration with different JSON libraries.
public interface Serializer<T> {
byte[] serialize(T t) throws SerializationException;
}public interface Deserializer<T> {
T deserialize(byte[] bytes) throws DeserializationException;
}public abstract class AbstractSerializer<T> implements Serializer<T> {
// Base implementation with common functionality
}
public abstract class AbstractDeserializer<T> implements Deserializer<T> {
// Base implementation with common functionality
}import io.jsonwebtoken.io.Serializer;
import io.jsonwebtoken.io.Deserializer;
import com.fasterxml.jackson.databind.ObjectMapper;
// Custom Jackson serializer
public class JacksonSerializer<T> implements Serializer<T> {
private final ObjectMapper objectMapper = new ObjectMapper();
@Override
public byte[] serialize(T object) throws SerializationException {
try {
return objectMapper.writeValueAsBytes(object);
} catch (Exception e) {
throw new SerializationException("Unable to serialize object", e);
}
}
}
// Custom Jackson deserializer
public class JacksonDeserializer<T> implements Deserializer<T> {
private final ObjectMapper objectMapper = new ObjectMapper();
private final Class<T> targetClass;
public JacksonDeserializer(Class<T> targetClass) {
this.targetClass = targetClass;
}
@Override
public T deserialize(byte[] bytes) throws DeserializationException {
try {
return objectMapper.readValue(bytes, targetClass);
} catch (Exception e) {
throw new DeserializationException("Unable to deserialize bytes", e);
}
}
}
// Usage in JWT operations
Serializer<Map<String, Object>> serializer = new JacksonSerializer<>();
Deserializer<Map<String, Object>> deserializer = new JacksonDeserializer<>(Map.class);
// Use custom serializers in JWT parsing
JwtParser parser = Jwts.parser()
.deserializer(deserializer)
.verifyWith(key)
.build();JJWT supports payload compression to reduce JWT size using standard compression algorithms.
public interface CompressionAlgorithm extends Identifiable {
String getId();
// Compression operations
byte[] compress(byte[] payload) throws CompressionException;
byte[] decompress(byte[] compressed) throws CompressionException;
}Available through Jwts.ZIP:
public static final class ZIP {
public static final CompressionAlgorithm DEF; // DEFLATE
public static final CompressionAlgorithm GZIP; // GZIP
}import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.CompressionAlgorithm;
// Create JWT with DEFLATE compression
CompressionAlgorithm deflate = Jwts.ZIP.DEF;
String compressedJwt = Jwts.builder()
.subject("user123")
.claim("largeData", Arrays.asList(/* large data object */))
.compressWith(deflate)
.signWith(key)
.compact();
// Decompression is automatic during parsing
JwtParser parser = Jwts.parser()
.verifyWith(key)
.build();
Jws<Claims> jws = parser.parseSignedClaims(compressedJwt);
Claims claims = jws.getPayload();
// Use GZIP compression
String gzipJwt = Jwts.builder()
.claim("data", largeDataSet)
.compressWith(Jwts.ZIP.GZIP)
.signWith(key)
.compact();public final class Base64Support {
// Utility methods for Base64 operations
public static boolean isBase64(CharSequence s);
public static boolean isBase64Url(CharSequence s);
}// Base64 Encoder Interface
public interface Base64Encoder extends Encoder<byte[], String> {
// Standard Base64 encoding
}
// Base64URL Encoder Interface
public interface Base64UrlEncoder extends Encoder<byte[], String> {
// Base64URL encoding (RFC 4648 Section 5)
}
// Base64 Decoder Interface
public interface Base64Decoder extends Decoder<CharSequence, byte[]> {
// Standard Base64 decoding
}
// Base64URL Decoder Interface
public interface Base64UrlDecoder extends Decoder<CharSequence, byte[]> {
// Base64URL decoding (RFC 4648 Section 5)
}public class ExceptionPropagatingEncoder<T, R> implements Encoder<T, R> {
// Wraps encoders to propagate specific exceptions
}
public class ExceptionPropagatingDecoder<T, R> implements Decoder<T, R> {
// Wraps decoders to propagate specific exceptions
}public interface Parser<T> {
T parse(CharSequence input) throws IOException;
}public interface ParserBuilder<T> extends Builder<Parser<T>> {
ParserBuilder<T> deserializer(Deserializer<T> deserializer);
Parser<T> build();
}import io.jsonwebtoken.io.Parser;
import io.jsonwebtoken.io.ParserBuilder;
// Custom JSON parser integration
Parser<Map<String, Object>> jsonParser = new ParserBuilder<Map<String, Object>>()
.deserializer(new JacksonDeserializer<>(Map.class))
.build();
// Parse JSON string
String jsonInput = "{\"sub\":\"user123\",\"exp\":1234567890}";
Map<String, Object> parsed = jsonParser.parse(jsonInput);public class IOException extends JwtException {
// Base exception for all IO operations
}public class CodecException extends IOException {
// General codec operation failures
}
public class EncodingException extends CodecException {
// Encoding operation failures
}
public class DecodingException extends CodecException {
// Decoding operation failures
}
public class SerializationException extends IOException {
// Serialization operation failures
}
public class DeserializationException extends IOException {
// Deserialization operation failures
}
public class SerialException extends IOException {
// Serial operation failures
}import io.jsonwebtoken.io.*;
try {
// Encode potentially problematic data
String encoded = Encoders.BASE64URL.encode(problematicData);
} catch (EncodingException e) {
System.err.println("Encoding failed: " + e.getMessage());
// Handle encoding failure
}
try {
// Decode potentially malformed input
byte[] decoded = Decoders.BASE64URL.decode(malformedInput);
} catch (DecodingException e) {
System.err.println("Decoding failed: " + e.getMessage());
// Handle decoding failure
}
try {
// Serialize complex object
byte[] serialized = customSerializer.serialize(complexObject);
} catch (SerializationException e) {
System.err.println("Serialization failed: " + e.getMessage());
// Handle serialization failure
}import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.JwtParser;
// Integrate with Gson
public class GsonIntegration {
private final Gson gson = new Gson();
public Serializer<Map<String, Object>> createSerializer() {
return new Serializer<Map<String, Object>>() {
@Override
public byte[] serialize(Map<String, Object> object) throws SerializationException {
try {
return gson.toJson(object).getBytes(StandardCharsets.UTF_8);
} catch (Exception e) {
throw new SerializationException("Gson serialization failed", e);
}
}
};
}
public Deserializer<Map<String, Object>> createDeserializer() {
return new Deserializer<Map<String, Object>>() {
@Override
public Map<String, Object> deserialize(byte[] bytes) throws DeserializationException {
try {
String json = new String(bytes, StandardCharsets.UTF_8);
Type type = new TypeToken<Map<String, Object>>(){}.getType();
return gson.fromJson(json, type);
} catch (Exception e) {
throw new DeserializationException("Gson deserialization failed", e);
}
}
};
}
}
// Use custom integration
GsonIntegration gsonIntegration = new GsonIntegration();
JwtParser parser = Jwts.parser()
.deserializer(gsonIntegration.createDeserializer())
.verifyWith(key)
.build();// Reuse encoder/decoder instances for better performance
public class JwtUtils {
private static final Encoder<byte[], String> ENCODER = Encoders.BASE64URL;
private static final Decoder<CharSequence, byte[]> DECODER = Decoders.BASE64URL;
public static String encodePayload(byte[] payload) {
return ENCODER.encode(payload);
}
public static byte[] decodePayload(String encoded) {
return DECODER.decode(encoded);
}
// Batch operations for better performance
public static List<String> encodeMultiple(List<byte[]> payloads) {
return payloads.stream()
.map(ENCODER::encode)
.collect(Collectors.toList());
}
}import io.jsonwebtoken.io.*;
public class TestUtils {
// Test data generation
public static byte[] generateTestData(int size) {
byte[] data = new byte[size];
new Random().nextBytes(data);
return data;
}
// Round-trip testing
public static boolean testEncodeDecode(byte[] original) {
try {
String encoded = Encoders.BASE64URL.encode(original);
byte[] decoded = Decoders.BASE64URL.decode(encoded);
return Arrays.equals(original, decoded);
} catch (Exception e) {
return false;
}
}
// Performance testing
public static long measureEncodePerformance(byte[] data, int iterations) {
long start = System.nanoTime();
for (int i = 0; i < iterations; i++) {
Encoders.BASE64URL.encode(data);
}
return System.nanoTime() - start;
}
}Install with Tessl CLI
npx tessl i tessl/maven-io-jsonwebtoken--jjwt-api