A comprehensive Java implementation of JSON Web Token (JWT) with creation, signing, and verification capabilities for server-side JVM applications.
—
Type-safe claim access system providing comprehensive methods for reading and converting JWT header and payload claims with automatic type conversion and null safety.
Generic interface for accessing claim values with type-safe conversion methods and null checking.
/**
* Generic claim value interface providing type-safe access to JWT claim values
*/
public interface Claim {
/**
* Whether this Claim has a null value or not.
* @return true if the Claim has a null value, false otherwise
*/
boolean isNull();
/**
* Whether this Claim is missing or not.
* @return true if the Claim is missing (not present in the JWT), false otherwise
*/
boolean isMissing();
/**
* Get this Claim as a Boolean.
* @return the Claim value as a Boolean or null if it can't be converted
*/
Boolean asBoolean();
/**
* Get this Claim as an Integer.
* @return the Claim value as an Integer or null if it can't be converted
*/
Integer asInt();
/**
* Get this Claim as a Long.
* @return the Claim value as a Long or null if it can't be converted
*/
Long asLong();
/**
* Get this Claim as a Double.
* @return the Claim value as a Double or null if it can't be converted
*/
Double asDouble();
/**
* Get this Claim as a String.
* @return the Claim value as a String or null if it can't be converted
*/
String asString();
/**
* Get this Claim as a Date.
* @return the Claim value as a Date or null if it can't be converted
*/
Date asDate();
/**
* Get this Claim as an Instant.
* @return the Claim value as an Instant or null if it can't be converted
*/
Instant asInstant();
/**
* Get this Claim as an Array of the given type.
* @param clazz the expected type of the array elements
* @return the Claim value as an Array or null if it can't be converted
*/
<T> T[] asArray(Class<T> clazz);
/**
* Get this Claim as a List of the given type.
* @param clazz the expected type of the list elements
* @return the Claim value as a List or null if it can't be converted
*/
<T> List<T> asList(Class<T> clazz);
/**
* Get this Claim as a Map of String to Object.
* @return the Claim value as a Map or null if it can't be converted
*/
Map<String, Object> asMap();
/**
* Get this Claim as a custom type using Jackson deserialization.
* @param clazz the expected type to deserialize to
* @return the Claim value as the requested type or null if it can't be converted
*/
<T> T as(Class<T> clazz);
}Usage Examples:
import com.auth0.jwt.interfaces.Claim;
import java.time.Instant;
import java.util.Date;
import java.util.List;
import java.util.Map;
DecodedJWT jwt = JWT.decode(token);
// Basic claim access with null checking
Claim roleClaim = jwt.getClaim("role");
if (!roleClaim.isMissing() && !roleClaim.isNull()) {
String role = roleClaim.asString();
System.out.println("User role: " + role);
}
// Type conversion examples
Claim ageClaim = jwt.getClaim("age");
Integer age = ageClaim.asInt(); // null if not convertible
Claim activeClaim = jwt.getClaim("isActive");
Boolean isActive = activeClaim.asBoolean(); // null if not convertible
Claim scoreClaim = jwt.getClaim("score");
Double score = scoreClaim.asDouble(); // null if not convertible
// Date handling
Claim lastLoginClaim = jwt.getClaim("lastLogin");
Date lastLoginDate = lastLoginClaim.asDate();
Instant lastLoginInstant = lastLoginClaim.asInstant();
// Array and List conversion
Claim rolesClaim = jwt.getClaim("roles");
String[] rolesArray = rolesClaim.asArray(String.class);
List<String> rolesList = rolesClaim.asList(String.class);
Claim scoresClaim = jwt.getClaim("scores");
Integer[] scoresArray = scoresClaim.asArray(Integer.class);
List<Integer> scoresList = scoresClaim.asList(Integer.class);
// Map conversion for complex objects
Claim metadataClaim = jwt.getClaim("metadata");
Map<String, Object> metadata = metadataClaim.asMap();
if (metadata != null) {
String region = (String) metadata.get("region");
Integer tier = (Integer) metadata.get("tier");
}
// Custom type deserialization
Claim userClaim = jwt.getClaim("user");
User user = userClaim.as(User.class); // Requires User to be JSON-deserializableAccess standard JWT registered claims as defined in RFC 7519.
/**
* Getter for the Issuer "iss" claim contained in the Payload.
* @return the Issuer value or null if it's not defined in the Payload
*/
String getIssuer();
/**
* Getter for the Subject "sub" claim contained in the Payload.
* @return the Subject value or null if it's not defined in the Payload
*/
String getSubject();
/**
* Getter for the Audience "aud" claim contained in the Payload.
* @return the Audience value as a List or an empty list if it's not defined in the Payload
*/
List<String> getAudience();
/**
* Getter for the Expires At "exp" claim contained in the Payload.
* @return the Expires At value as a Date or null if it's not defined in the Payload
*/
Date getExpiresAt();
/**
* Getter for the Expires At "exp" claim contained in the Payload as an Instant.
* @return the Expires At value as an Instant or null if it's not defined in the Payload
*/
Instant getExpiresAtAsInstant();
/**
* Getter for the Not Before "nbf" claim contained in the Payload.
* @return the Not Before value as a Date or null if it's not defined in the Payload
*/
Date getNotBefore();
/**
* Getter for the Not Before "nbf" claim contained in the Payload as an Instant.
* @return the Not Before value as an Instant or null if it's not defined in the Payload
*/
Instant getNotBeforeAsInstant();
/**
* Getter for the Issued At "iat" claim contained in the Payload.
* @return the Issued At value as a Date or null if it's not defined in the Payload
*/
Date getIssuedAt();
/**
* Getter for the Issued At "iat" claim contained in the Payload as an Instant.
* @return the Issued At value as an Instant or null if it's not defined in the Payload
*/
Instant getIssuedAtAsInstant();
/**
* Getter for the JWT ID "jti" claim contained in the Payload.
* @return the JWT ID value or null if it's not defined in the Payload
*/
String getId();Usage Examples:
DecodedJWT jwt = JWT.decode(token);
// Standard registered claims
String issuer = jwt.getIssuer(); // "iss" - who issued the token
String subject = jwt.getSubject(); // "sub" - token subject (usually user ID)
List<String> audience = jwt.getAudience(); // "aud" - intended audience
String jwtId = jwt.getId(); // "jti" - unique token identifier
System.out.println("Token issued by: " + issuer);
System.out.println("Token subject: " + subject);
System.out.println("Token audiences: " + audience);
// Time-based claims with Date
Date expiresAt = jwt.getExpiresAt(); // "exp" - expiration time
Date notBefore = jwt.getNotBefore(); // "nbf" - not valid before
Date issuedAt = jwt.getIssuedAt(); // "iat" - issued at time
if (expiresAt != null) {
System.out.println("Token expires at: " + expiresAt);
boolean isExpired = expiresAt.before(new Date());
System.out.println("Token expired: " + isExpired);
}
// Time-based claims with Instant (preferred for modern Java)
Instant expiresAtInstant = jwt.getExpiresAtAsInstant();
Instant notBeforeInstant = jwt.getNotBeforeAsInstant();
Instant issuedAtInstant = jwt.getIssuedAtAsInstant();
if (expiresAtInstant != null) {
boolean isExpired = expiresAtInstant.isBefore(Instant.now());
long secondsUntilExpiry = Duration.between(Instant.now(), expiresAtInstant).getSeconds();
System.out.println("Seconds until expiry: " + secondsUntilExpiry);
}Access custom claims from the JWT payload with type-safe conversion.
/**
* Get a custom Claim given its name from the Payload.
* @param name the name of the Claim to retrieve
* @return a valid Claim instance if the Claim was found or a NullClaim if not
*/
Claim getClaim(String name);
/**
* Get all Claims contained in the Payload.
* @return a Map containing all the custom Claims defined in the token
*/
Map<String, Claim> getClaims();Usage Examples:
DecodedJWT jwt = JWT.decode(token);
// Single custom claim access
Claim roleClaim = jwt.getClaim("role");
Claim departmentClaim = jwt.getClaim("department");
Claim permissionsClaim = jwt.getClaim("permissions");
// Safe access with validation
if (!roleClaim.isMissing()) {
String role = roleClaim.asString();
System.out.println("User role: " + role);
}
// Complex custom claim handling
Claim levelClaim = jwt.getClaim("level");
if (!levelClaim.isMissing() && !levelClaim.isNull()) {
Integer level = levelClaim.asInt();
if (level != null && level >= 5) {
System.out.println("User has administrator privileges");
}
}
// Array claims
Claim rolesClaim = jwt.getClaim("roles");
if (!rolesClaim.isMissing()) {
List<String> roles = rolesClaim.asList(String.class);
if (roles != null && roles.contains("admin")) {
System.out.println("User is an administrator");
}
}
// Get all claims for inspection
Map<String, Claim> allClaims = jwt.getClaims();
System.out.println("Token contains " + allClaims.size() + " claims:");
for (Map.Entry<String, Claim> entry : allClaims.entrySet()) {
String claimName = entry.getKey();
Claim claimValue = entry.getValue();
if (!claimValue.isMissing() && !claimValue.isNull()) {
// Convert to string for display (may not always be appropriate)
String displayValue = claimValue.asString();
System.out.println(" " + claimName + ": " + displayValue);
}
}Access JWT header claims including standard header parameters and custom header claims.
/**
* Getter for the Algorithm "alg" claim contained in the Header.
* @return the Algorithm defined or null if it's not defined in the Header
*/
String getAlgorithm();
/**
* Getter for the Type "typ" claim contained in the Header.
* @return the Type defined or null if it's not defined in the Header
*/
String getType();
/**
* Getter for the Content Type "cty" claim contained in the Header.
* @return the Content Type defined or null if it's not defined in the Header
*/
String getContentType();
/**
* Getter for the Key Id "kid" claim contained in the Header.
* @return the Key Id defined or null if it's not defined in the Header
*/
String getKeyId();
/**
* Get a custom Claim given its name from the Header.
* @param name the name of the Claim to retrieve
* @return a valid Claim instance if the Claim was found or a NullClaim if not
*/
Claim getHeaderClaim(String name);Usage Examples:
DecodedJWT jwt = JWT.decode(token);
// Standard header claims
String algorithm = jwt.getAlgorithm(); // "alg" - signing algorithm
String type = jwt.getType(); // "typ" - token type (usually "JWT")
String contentType = jwt.getContentType(); // "cty" - content type
String keyId = jwt.getKeyId(); // "kid" - key identifier
System.out.println("Token algorithm: " + algorithm);
System.out.println("Token type: " + type);
System.out.println("Key ID: " + keyId);
// Custom header claims
Claim customHeaderClaim = jwt.getHeaderClaim("custom");
if (!customHeaderClaim.isMissing()) {
String customValue = customHeaderClaim.asString();
System.out.println("Custom header claim: " + customValue);
}
// Application-specific header claims
Claim versionClaim = jwt.getHeaderClaim("version");
Claim instanceClaim = jwt.getHeaderClaim("instance");
if (!versionClaim.isMissing()) {
String version = versionClaim.asString();
System.out.println("Token version: " + version);
}Common patterns for safely validating and processing claims.
Usage Examples:
DecodedJWT jwt = JWT.decode(token);
// Safe string claim validation
public String getValidatedRole(DecodedJWT jwt) {
Claim roleClaim = jwt.getClaim("role");
if (roleClaim.isMissing() || roleClaim.isNull()) {
return "guest"; // default role
}
String role = roleClaim.asString();
if (role == null || role.trim().isEmpty()) {
return "guest";
}
// Validate against allowed roles
Set<String> allowedRoles = Set.of("admin", "user", "guest", "moderator");
return allowedRoles.contains(role) ? role : "guest";
}
// Safe numeric claim validation
public int getValidatedLevel(DecodedJWT jwt) {
Claim levelClaim = jwt.getClaim("level");
if (levelClaim.isMissing() || levelClaim.isNull()) {
return 0;
}
Integer level = levelClaim.asInt();
if (level == null) {
return 0;
}
// Ensure level is within valid range
return Math.max(0, Math.min(level, 10));
}
// Safe array claim validation
public List<String> getValidatedPermissions(DecodedJWT jwt) {
Claim permissionsClaim = jwt.getClaim("permissions");
if (permissionsClaim.isMissing() || permissionsClaim.isNull()) {
return Collections.emptyList();
}
List<String> permissions = permissionsClaim.asList(String.class);
if (permissions == null) {
return Collections.emptyList();
}
// Filter out null/empty permissions and validate against allowed set
Set<String> allowedPermissions = Set.of("read", "write", "delete", "admin");
return permissions.stream()
.filter(Objects::nonNull)
.filter(p -> !p.trim().isEmpty())
.filter(allowedPermissions::contains)
.collect(Collectors.toList());
}
// Safe date claim validation
public Instant getValidatedLastLogin(DecodedJWT jwt) {
Claim lastLoginClaim = jwt.getClaim("lastLogin");
if (lastLoginClaim.isMissing() || lastLoginClaim.isNull()) {
return null;
}
Instant lastLogin = lastLoginClaim.asInstant();
if (lastLogin == null) {
return null;
}
// Ensure date is not in the future and not too old
Instant now = Instant.now();
Instant oneYearAgo = now.minus(365, ChronoUnit.DAYS);
if (lastLogin.isAfter(now) || lastLogin.isBefore(oneYearAgo)) {
return null; // Invalid date range
}
return lastLogin;
}Constants for standard JWT claim names and header parameters.
/**
* Standard JWT claim names from RFC 7519
*/
public class RegisteredClaims {
public static final String ISSUER = "iss";
public static final String SUBJECT = "sub";
public static final String AUDIENCE = "aud";
public static final String EXPIRES_AT = "exp";
public static final String NOT_BEFORE = "nbf";
public static final String ISSUED_AT = "iat";
public static final String JWT_ID = "jti";
}
/**
* JWT header parameter constants
*/
public class HeaderParams {
public static final String ALGORITHM = "alg";
public static final String CONTENT_TYPE = "cty";
public static final String TYPE = "typ";
public static final String KEY_ID = "kid";
}Usage Examples:
import static com.auth0.jwt.RegisteredClaims.*;
import static com.auth0.jwt.HeaderParams.*;
// Use constants for claim names
DecodedJWT jwt = JWT.decode(token);
String issuer = jwt.getClaim(ISSUER).asString();
String subject = jwt.getClaim(SUBJECT).asString();
List<String> audience = jwt.getClaim(AUDIENCE).asList(String.class);
// Use constants for header parameters
String algorithm = jwt.getHeaderClaim(ALGORITHM).asString();
String keyId = jwt.getHeaderClaim(KEY_ID).asString();
// Better for consistency and avoiding typos
Claim expClaim = jwt.getClaim(EXPIRES_AT);
Claim iatClaim = jwt.getClaim(ISSUED_AT);/**
* JWT payload interface providing access to payload claims
*/
public interface Payload {
String getIssuer();
String getSubject();
List<String> getAudience();
Date getExpiresAt();
Instant getExpiresAtAsInstant();
Date getNotBefore();
Instant getNotBeforeAsInstant();
Date getIssuedAt();
Instant getIssuedAtAsInstant();
String getId();
Claim getClaim(String name);
Map<String, Claim> getClaims();
}
/**
* JWT header interface providing access to header claims
*/
public interface Header {
String getAlgorithm();
String getType();
String getContentType();
String getKeyId();
Claim getHeaderClaim(String name);
}
/**
* Generic claim value interface with type-safe conversion methods
*/
public interface Claim {
boolean isNull();
boolean isMissing();
Boolean asBoolean();
Integer asInt();
Long asLong();
Double asDouble();
String asString();
Date asDate();
Instant asInstant();
<T> T[] asArray(Class<T> clazz);
<T> List<T> asList(Class<T> clazz);
Map<String, Object> asMap();
<T> T as(Class<T> clazz);
}Install with Tessl CLI
npx tessl i tessl/maven-com-auth0--java-jwt