In this blog we will understand what a JWT is, what it can contain, where it is used and how can you create and parse a JWT in Java.
Table of Contents
The code for this blog can be found at – JWTDemo.java and JWTDemoTest.java.
1.0 What is JWT
Before we look into how to create and parse JWT in Java, lets first understand a little bit more about JWT in this section.
JWT (pronounced as jots) is short of Json Web Tokens.
As per jwt.io, JSON Web Token (JWT) is an open standard (RFC 7519) that defines a compact and self-contained way for securely transmitting information between parties as a JSON object.
The first question that comes to mind is what is so special about JWT? How is it different from any other token that can be for authentication?
The primary difference lies in following
- The payload contains
JSON
data that contains various claims, which are nothing but key/value pairs that carry information about the subject - It is digital signed and can be verified. The tokens are signed either using a private secret or a public/private key.
A very common scenario where JWT is used is for authentication/auth, and the workflow would look like this

2.0 JWT Structure
Any JWT might look like this sample given below.
eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiI4ZWY2ZGU5MC1hMzljLTRhMjgtOTBmYy0xY2MyZmViZjFhMzciLCJzdWIiOiJzdW5pdEBnbWFpbC5jb20iLCJpc3MiOiJEZW1vIEFwcCIsImlhdCI6MTU5NzYwNDYwNywiZXhwIjoxMDIzNzUxODIwNywiZmlyc3ROYW1lIjoiU3VuaXQiLCJsYXN0TmFtZSI6IkNoYXR0ZXJqZWUiLCJpc0FkbWluIjp0cnVlfQ.VvvfRsZ75erZ6-k1-BeAI3IS6yXCM_3p5jSsxPCFkfI
If you look closely it has three parts separated by dot ( .
) in format of xxxx.yyyy.zzzz
These parts are
- Header
- Payload
- Signature
Let’s look at below image on how a given sample JWT looks like when broken into its parts.

You can decode the payload of a JWT at jwt.io or jsonwebtoken.io
We will look at each part one be one in below sections.
2.1 JWT Header & Signing Algorithms
Header of an JWT contains two information
- Type of token. e.g JWT
- Signing algorithm used. The most common signing alogrithm is HMAC + SHA256 which is also known as
HS256
.
Typically the header json would look like this.
{
"alg": "HS256",
"typ": "JWT"
}
The most common signing algorithm HMAC + SHA
, which uses a secret key for signing the JWT.
Algorithm | Detail | Minimum Size of Secret Key |
HS256 | HMAC + SHA256 | 256 bits = 32 bytes |
HS384 | HMAC + SHA384 | 384 bits = 48 bytes |
HS512 | HMAC + SHA512 | 512 bits = 64 bytes |
However you can also use asymmetric key based algorithms like RSA
or Elliptic Curve
.
2.2 JWT Claims
Claims are key/value pairs that contains information about the subject.
A claim payload JSON might look like this
{
"jti": "8aa9d2fd-8000-457c-a0cd-4e366d349564",
"sub": "sunit@gmail.com",
"iss": "Demo App",
"iat": 1597594524,
"exp": 10237508124,
"firstName": "Sunit",
"lastName": "Chatterjee",
"isAdmin": true
}
There are two types of claims
- Reserved claims or standard claims
- Custom claims (which can be any keys/value pair the server wants to send to client)
In above example jti
, sub
, iss
, iat
, exp
are reserved claims and firstName
, lastName
, isAdmin
are custom claims.
Some of the reserved claims are
Claim | Claim Information | Claim Description |
iss | Issuer | Who issued this JWT |
sub | Subject | Typically the user |
aud | Audience | Who the JWT recipient |
iat | Issued At | When JWT was created/issued |
exp | Expiration Time | Time after which JWT expires |
nbf | Not Before Time | Time before which JWT cannot be used |
jti | JWT ID | Unique identified that prevents a JWT to be used again. |
Could you think of a typical scenario where you may need all three claim – iat
, exp
and nbf
?
A simple use case can be that we are giving a 4 hour access of an API to a client at 12pm next day. In that case
iat
– would be set to current timenbf
– would beset to 12pm next dayexp
– would be set to 4 pm next day
2.3 JWT Signature
The signature is primarily used to verify that the JWT was not tampered in any way.
Typically Signature is created using encoded Header and encoded Payload and a Secret Key.
HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
secret)
3.0 Creating & Parsing JWT
We have spent lot of time at theory. Now lets get our hands dirtly and write code to generate and parse a JWT
3.1 Adding library dependencies
If you are using Gradle, the add following dependencies
compile 'io.jsonwebtoken:jjwt-api:0.11.2'
runtime 'io.jsonwebtoken:jjwt-impl:0.11.2'
runtime 'io.jsonwebtoken:jjwt-jackson:0.11.2'
If you intend to use RSASSA-PSS (PS256, PS384, PS512)
algorithms, then add following dependency
runtime 'org.bouncycastle:bcprov-jdk15on:1.60'
If you intend to use GSON
instead of Jackson
for Json Parsing then add following dependency
runtime 'io.jsonwebtoken:jjwt-gson:0.11.2'
3.2 Creating JWT
Let’s create a JWT now.
We will use
HS256
Algorithm to create our JWT and it only requires a sameSecretKey
to be used both for creating and parsing the JWT.
First we need to generate a HMAC-SHA
key for signing the JWT.
For this we will need a 256 bit Secret (String
) and then generate the SecretKey
String secret = "9aaa4aba-6c85-4524-a72a-1021caf2e025";
byte[] secretInBytes = secret.getBytes("UTF-8");
SecretKey key = Keys.hmacShaKeyFor(secretInBytes);
The above method automatically chooses the right algorithm HS256
/ HS384
/ HS512
based on the length of secret byte
array.
In case you want to generate a random Secret Key based on HMAC algorithm, you can use below code for it
SecretKey key = Keys.secretKeyFor(SignatureAlgorithm.HS256);
If you provided a secret that is smaller than required size of the
SignatureAlgorithm
, then you will get aWeakKeyException
.
Now that secret key is created lets create a JWT and add some claims to it.
We will do this using Jwts.builder()
to create the JWT and use its setter
methods to set the claims.
//Generate secret key as shown above
SecretKey secretKey = Keys.hmacShaKeyFor(...);
Date currentTime = Date.from(Instant.now());
Date expiryTime =
Date.from(Instant.now().plus(Duration.ofSeconds(60)));
String jwt =
Jwts.builder()
.setId(UUID.randomUUID().toString()) //random jti
.setSubject("sunit@gmail.com")
.setIssuer("Demo App")
.setIssuedAt(currentTime)
.setExpiration(expiryTime)
.claim("firstName", "Sunit")
.claim("lastName", "Chatterjee")
.claim("isAdmin", true)
.signWith(secretKey)
.compact();
Above code will generate a JWT with below payload.
{
"jti": "0aaa8807-8f88-4867-b718-3bc8f90cda9b",
"sub": "sunit@gmail.com",
"iss": "Demo App",
"iat": 1597607949,
"exp": 1597608009,
"firstName": "Sunit",
"lastName": "Chatterjee",
"isAdmin": true
}
3.3 Parsing JWT and Extracting claims
We will use the same class io.jsonwebtoken.Jwts
to parse a JWT token and get claims.
Jws<Claims> headerClaimsJwt =
Jwts.parserBuilder()
.setSigningKey(secretKey)
.build()
.parseClaimsJws(jwtString);
Claims claims = headerClaimsJwt.getBody();
In above code we need to use the same SecretKey
that was used to create the JWT.
We can get claim information from the Claims
object as shown below
// Get Reserved Claims
String issuer = claims.getIssuer();
String subject = claims.getSubject();
// Get Custom claims
String firstName = claims.get("firstName", String.class);
boolean isAdmin = claims.get("isAdmin", Boolean.class);
You can also get some exceptions while parsing the JWT.
SignatureException
– If different key is used to parse the JWT, than what was used to create it.ExpiredJwtException
– If JWT is expired.MalformedJwtException
– If JWT structure is incorrect.IllegalArgumentException
– If JWT is null or empty string.
With this we come to end of our current blog.
The code for this blog can be found at – JWTDemo.java and JWTDemoTest.java.