io.jsonwebtoken / jjwt

JJWT API
Documentation

The most popular Java / Android library for creating and verifying JSON Web Tokens (JWT), JSON Web Signatures (JWS), and JSON Web Encryption (JWE). Built on top of RFC 7519.

JDK 8+ Android v0.12.6 RFC 7519

Installation #installation

Add the following dependencies to your build file. Include only the implementation you need.

Maven

XML<!-- Core API -->
<dependency>
  <groupId>io.jsonwebtoken</groupId>
  <artifactId>jjwt-api</artifactId>
  <version>0.12.6</version>
</dependency>

<!-- Runtime: choose jackson, gson, or orgjson -->
<dependency>
  <groupId>io.jsonwebtoken</groupId>
  <artifactId>jjwt-impl</artifactId>
  <version>0.12.6</version>
  <scope>runtime</scope>
</dependency>
<dependency>
  <groupId>io.jsonwebtoken</groupId>
  <artifactId>jjwt-jackson</artifactId>
  <version>0.12.6</version>
  <scope>runtime</scope>
</dependency>

Gradle

Groovyimplementation 'io.jsonwebtoken:jjwt-api:0.12.6'
runtimeOnly  'io.jsonwebtoken:jjwt-impl:0.12.6'
runtimeOnly  'io.jsonwebtoken:jjwt-jackson:0.12.6'

Quick Start #quickstart

Create and verify a signed JWT in under 10 lines of code.

Create a Token

Javaimport io.jsonwebtoken.Jwts;
import io.jsonwebtoken.security.Keys;
import javax.crypto.SecretKey;

// Generate a secure key (store it safely!)
SecretKey key = Keys.hmacShaKeyFor(secretBytes); // or Keys.secretKeyFor(SignatureAlgorithm.HS256)

String jwt = Jwts.builder()
    .subject("user123")
    .issuer("myapp")
    .issuedAt(new Date())
    .expiration(new Date(System.currentTimeMillis() + 86_400_000L)) // 1 day
    .claim("role", "admin")
    .signWith(key)
    .compact();

Parse & Verify a Token

JavaClaims claims = Jwts.parser()
    .verifyWith(key)
    .build()
    .parseSignedClaims(jwt)
    .getPayload();

String subject = claims.getSubject(); // "user123"
String role    = claims.get("role", String.class); // "admin"
💡 Tip If parsing throws no exception, the token is valid — signature verified, expiry checked, and all configured claims validated automatically.

Jwts Factory #jwts

The Jwts class is the main entry point. All operations start here.

MethodReturn TypeDescription
Jwts.builder()JwtBuilderCreates a new JWT/JWS/JWE builder.
Jwts.parser()JwtParserBuilderCreates a new JWT parser builder.
Jwts.claims()ClaimsBuilderCreates a new Claims builder (payload).
Jwts.header()DynamicHeaderBuilderCreates a new JWT header builder.
Jwts.SIGStandardSignatureAlgorithmsRegistry of all JWS signature algorithms.
Jwts.KEYStandardKeyAlgorithmsRegistry of JWE key management algorithms.
Jwts.ENCStandardEncryptionAlgorithmsRegistry of JWE content encryption algorithms.
Jwts.ZIPStandardCompressionAlgorithmsRegistry of compression codecs.

JWT Builder #builder

Fluent API for constructing a token. Call compact() at the end to get the serialized string.

HEADER header() Set custom header parameters

Returns a JwtBuilder after setting the JOSE header. Use the consumer overload for complex headers.

JavaJwts.builder()
    .header().add("kid", "my-key-id").and()
    ...
CLAIMS Claims setters RFC 7519 registered claims
MethodClaimType
.issuer(s)issString
.subject(s)subString
.audience()audString / Set<String>
.expiration(date)expDate (NumericDate)
.notBefore(date)nbfDate (NumericDate)
.issuedAt(date)iatDate (NumericDate)
.id(s)jtiString
.claim(name, val)customObject
.claims(map)multiple customMap<String,?>
SIGN signWith(key) Produce a JWS (signed JWT)

JJWT automatically selects the strongest algorithm appropriate for the key type. You may also specify the algorithm explicitly.

Java// Auto algorithm selection (recommended)
.signWith(secretKey)

// Explicit algorithm
.signWith(secretKey, Jwts.SIG.HS512)

// RSA / EC private key
.signWith(privateKey, Jwts.SIG.RS256)
ENCRYPT encryptWith(key, keyAlg, encAlg) Produce a JWE (encrypted JWT)
JavaSecretKey aesKey = Jwts.KEY.A256GCMKW.key().build();

String jwe = Jwts.builder()
    .subject("alice")
    .encryptWith(aesKey, Jwts.KEY.A256GCMKW, Jwts.ENC.A256GCM)
    .compact();

Claims Interface #claims

The Claims interface extends Map<String, Object> and provides typed accessors for all registered claims.

MethodClaimReturns
getIssuer()issString
getSubject()subString
getAudience()audSet<String>
getExpiration()expDate
getNotBefore()nbfDate
getIssuedAt()iatDate
getId()jtiString
get(name, Class<T>)customT

JWT Parser #parser

All parsing starts with Jwts.parser(). The builder configures verification and then creates an immutable, thread-safe parser.

JwtParserBuilder Methods

MethodDescription
.verifyWith(key)Set a secret or public key for signature verification.
.verifyWith(keyLocator)Provide a Locator<SecretKey> / Locator<PublicKey> for key-per-token lookup.
.decryptWith(key)Set decryption key for JWE tokens.
.decryptWith(keyLocator)Dynamic key locator for JWE.
.requireIssuer(s)Require iss claim to equal value.
.requireSubject(s)Require sub claim.
.requireAudience(s)Require aud to contain value.
.requireExpiration(date)Require exp to equal value.
.requireIssuedAt(date)Require iat.
.require(claim, value)Require any custom claim to equal value.
.clockSkewSeconds(n)Allow up to n seconds of clock skew.
.clock(clock)Provide a custom Clock for time-based checks.
.build()Returns an immutable JwtParser.

JwtParser Parse Methods

MethodReturnsUse When
parseSignedClaims(jwt)Jws<Claims>Standard signed JWT with claims payload
parseSignedContent(jwt)Jws<byte[]>Signed JWT with arbitrary byte content
parseEncryptedClaims(jwt)Jwe<Claims>Encrypted JWT with claims payload
parseEncryptedContent(jwt)Jwe<byte[]>Encrypted JWT with arbitrary content
parseUnsecuredClaims(jwt)Jwt<Header,Claims>Unsecured JWT (alg=none) — use with caution
parse(jwt)Jwt<?,?>Unknown type — returns most specific interface
Java// Thread-safe parser — create once, reuse everywhere
JwtParser parser = Jwts.parser()
    .verifyWith(publicKey)
    .requireIssuer("auth-service")
    .clockSkewSeconds(30)
    .build();

// Parse
Jws<Claims> jws = parser.parseSignedClaims(token);
Claims payload  = jws.getPayload();
JwsHeader header = jws.getHeader();

Keys & Key Generation #keys

Use the Keys utility class to safely generate or construct cryptographic keys.

Javaimport io.jsonwebtoken.security.Keys;

// ── HMAC Secret Keys ───────────────────────────────────────────
SecretKey hs256 = Jwts.SIG.HS256.key().build();
SecretKey hs384 = Jwts.SIG.HS384.key().build();
SecretKey hs512 = Jwts.SIG.HS512.key().build();

// From existing bytes (must be long enough for chosen alg)
SecretKey key = Keys.hmacShaKeyFor(Decoders.BASE64.decode(base64Secret));

// ── RSA Key Pair ───────────────────────────────────────────────
KeyPair rsaPair = Jwts.SIG.RS256.keyPair().build();  // 2048-bit
KeyPair ps512   = Jwts.SIG.PS512.keyPair().build();  // 4096-bit

// ── EC Key Pair ────────────────────────────────────────────────
KeyPair ec256 = Jwts.SIG.ES256.keyPair().build();   // P-256
KeyPair ec384 = Jwts.SIG.ES384.keyPair().build();   // P-384
KeyPair ec512 = Jwts.SIG.ES512.keyPair().build();   // P-521

// ── EdDSA (Ed25519) ────────────────────────────────────────────
KeyPair ed25519 = Jwts.SIG.Ed25519.keyPair().build();
⚠ Key Security Never hard-code secret keys. Load them from environment variables, a secrets manager (HashiCorp Vault, AWS Secrets Manager), or a Hardware Security Module (HSM). Rotate keys regularly.

HMAC Signature Algorithms #hmac

Available via Jwts.SIG.*. All require a SecretKey.

IdentifierAlgorithmMin Key LengthUse Case
HS256HMAC-SHA-256256 bits (32 bytes)Default, widely supported
HS384HMAC-SHA-384384 bits (48 bytes)Moderate security
HS512HMAC-SHA-512512 bits (64 bytes)High security

RSA Signature Algorithms #rsa

Sign with a PrivateKey, verify with the corresponding PublicKey.

IdentifierAlgorithmMin Key Size
RS256RSASSA-PKCS1-v1_5 + SHA-2562048 bits
RS384RSASSA-PKCS1-v1_5 + SHA-3842048 bits
RS512RSASSA-PKCS1-v1_5 + SHA-5124096 bits
PS256RSASSA-PSS + SHA-2562048 bits
PS384RSASSA-PSS + SHA-3842048 bits
PS512RSASSA-PSS + SHA-5124096 bits

Elliptic Curve Algorithms #ec

IdentifierCurveSignature Size
ES256P-256 + SHA-25664 bytes
ES384P-384 + SHA-38496 bytes
ES512P-521 + SHA-512132 bytes

EdDSA (OKP) Algorithms #eddsa

Requires JDK 15+ or Bouncy Castle on older JDKs.

IdentifierCurveNotes
Ed25519Edwards 25519Fast, secure, 64-byte signature
Ed448Edwards 448Higher security, 114-byte signature

JSON Web Encryption (JWE) #jwe

JJWT supports full JWE token creation and parsing. JWE requires two algorithm choices:

Key Management Algorithm

How the Content Encryption Key (CEK) is protected. E.g. A256GCMKW, RSA-OAEP.

Content Encryption Algorithm

How the JWT payload is encrypted. E.g. A256GCM, A128CBC-HS256.

Java// ── Encrypt ────────────────────────────────────────────────────
SecretKey encKey = Jwts.ENC.A256GCM.key().build();

String jwe = Jwts.builder()
    .subject("bob")
    .encryptWith(encKey, Jwts.KEY.A256GCMKW, Jwts.ENC.A256GCM)
    .compact();

// ── Decrypt ────────────────────────────────────────────────────
Claims claims = Jwts.parser()
    .decryptWith(encKey)
    .build()
    .parseEncryptedClaims(jwe)
    .getPayload();

JWE Key Algorithms #jwe-algorithms

Jwts.KEY.*RFC NameKey Type
RSA1_5RSAES-PKCS1-v1_5RSA
RSA_OAEPRSAES-OAEP + SHA-1RSA
RSA_OAEP_256RSAES-OAEP + SHA-256RSA
A128KWAES Key Wrap 128AES SecretKey
A192KWAES Key Wrap 192AES SecretKey
A256KWAES Key Wrap 256AES SecretKey
A128GCMKWAES-GCM Key Wrap 128AES SecretKey
A192GCMKWAES-GCM Key Wrap 192AES SecretKey
A256GCMKWAES-GCM Key Wrap 256AES SecretKey
ECDH_ESECDH-ESEC / OKP
PBES2_HS256_A128KWPBES2 + AES-128Password
PBES2_HS384_A192KWPBES2 + AES-192Password
PBES2_HS512_A256KWPBES2 + AES-256Password
DIRECTDirect Key AgreementAES SecretKey

JWE Content Encryption #jwe-enc

Jwts.ENC.*RFC NameCEK Size
A128CBC_HS256AES-128-CBC + HMAC-SHA-256256 bits
A192CBC_HS384AES-192-CBC + HMAC-SHA-384384 bits
A256CBC_HS512AES-256-CBC + HMAC-SHA-512512 bits
A128GCMAES-128-GCM128 bits
A192GCMAES-192-GCM192 bits
A256GCMAES-256-GCM256 bits

Exceptions #exceptions

All JJWT exceptions extend JwtException. Handle them to give meaningful error responses.

Exception ClassWhen Thrown
JwtExceptionBase class for all JJWT exceptions.
MalformedJwtExceptionThe string is not a valid JWT structure.
ExpiredJwtExceptionThe exp claim is in the past.
PrematureJwtExceptionThe nbf claim is in the future.
MissingClaimExceptionA required claim is absent.
IncorrectClaimExceptionA required claim has the wrong value.
SignatureExceptionSignature verification failed.
SecurityExceptionKey is too weak for the chosen algorithm.
UnsupportedJwtExceptionToken type/alg not supported by this parser.
Javatry {
    Claims claims = parser.parseSignedClaims(token).getPayload();
} catch (ExpiredJwtException e) {
    // 401 - token expired
} catch (SignatureException e) {
    // 401 - tampered token
} catch (MalformedJwtException e) {
    // 400 - bad token format
} catch (JwtException e) {
    // 401 - catch-all
}

Compression #compression

Reduce token size when claims are large. Available via Jwts.ZIP.

⚠ Interoperability Compression is a JJWT extension (non-standard for JWS). Only use it when both endpoints use JJWT or a compatible library.
Jwts.ZIP.*Algorithm
DEFDEFLATE (RFC 1951) — widely supported
GZIPGZIP — better ratio, less support
JavaString compressedJwt = Jwts.builder()
    .claims(largeClaims)
    .compressWith(Jwts.ZIP.DEF)
    .signWith(key)
    .compact();

// Decompression is automatic when parsing
Claims claims = Jwts.parser()
    .verifyWith(key)
    .build()
    .parseSignedClaims(compressedJwt)
    .getPayload();

Migration Guide (0.11 → 0.12) #migration

Version 0.12 introduces a cleaner, more type-safe API. Key breaking changes:

Replace deprecated claim setters

setSubject()subject(), setExpiration()expiration(), setIssuedAt()issuedAt(), etc. All setters are now builder methods without the "set" prefix.

Replace SignatureAlgorithm enum

SignatureAlgorithm.HS256Jwts.SIG.HS256. The old enum is removed.

Replace deprecated key helpers

Keys.secretKeyFor(SignatureAlgorithm.HS256)Jwts.SIG.HS256.key().build()

Update parser call

Jwts.parserBuilder()Jwts.parser(), .setSigningKey().verifyWith()

Update parse method names

.parseClaimsJws().parseSignedClaims(), .parseClaimsJwt().parseUnsecuredClaims()

ℹ Full Changelog See github.com/jwtk/jjwt/blob/master/CHANGELOG.md for the complete list of changes between versions.