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

∆ Top

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.

AlgorithmDetailMinimum Size of Secret Key
HS256HMAC + SHA256256 bits = 32 bytes
HS384HMAC + SHA384384 bits = 48 bytes
HS512HMAC + SHA512512 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

ClaimClaim InformationClaim Description
issIssuerWho issued this JWT
subSubjectTypically the user
audAudienceWho the JWT recipient
iatIssued AtWhen JWT was created/issued
expExpiration TimeTime after which JWT expires
nbfNot Before TimeTime before which JWT cannot be used
jtiJWT IDUnique 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 time
  • nbf – would beset to 12pm next day
  • exp – 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)

∆ Top

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 same SecretKey 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 a WeakKeyException.

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.

∆ Top

With this we come to end of our current blog.

The code for this blog can be found at – JWTDemo.java and JWTDemoTest.java.