Demystifying JSON Web Token (JWT) Part-1

JSON Web Token or JWT or sometimes pronounced as 'jot' is an open standard (RFC-7519) for transferring claims in a compact, printable and secure manner along with a signature that provide its authenticity between two parties as a JSON object.

JWTs can be signed using JSON Web Signature (RFC-7515) and/or encrypted using JSON Web Encryption (RFC-7516) and that provides a powerful and secured solution for transferring information in many different situations.

In this section we will focus on unencrypted JWTs, and will take the encrypted one in next part.

Structure of JWT

JWT's contains 3 different components separated by dots(.)

  • Header
  • Payload
  • Signature/Encryption Data

The header and payload are mandatory and have certain structure(JSON). The third part(not a JSON object itself) which is signature depends upon the algorithm used for signing and can be omitted in case of unsecured/unencrypted JWTs.

JWT usage URL safe base64 encoding where '+' and '/' are substituted by '-' and   '_' characters respectively. The resulting sequence is a string with format header.payload.signature and look like the following,

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

In this example, the base64url decoded header is

{
  "alg": "HS256",
  "typ": "JWT"
}

the decoded payload is

{
  "sub": "1234567890",
  "name": "John Doe",
  "iat": 1516239022
}

and the last part is the secret required to verify the signature.

Now lets see the details of mandatory part of JWT which is the header and the payload.

Also known as JOSE(JSON Object Signing and Encryption) Header is the first part of JWT token. There can be several fields in the header depends upon the type of JWT, for example, the only mandatory field for the unencrypted JWT is alg with value as none. For a signed JWTs, some fields can be alg, jku, kid, typ.

The header part is a JSON object and has the following format

{
  "alg": "RS256", // none in case of unencrypted jwt
  "jku": "url to the public key set",
  "kid": "key-id-1", //optional
  "typ": "JWT"
}

It is possible to add additional user defined claims to the header.

Payload

Just like the header, payload is a JSON object. This is the part where all the user related data is added. It can contain claims with specific meaning known as registered claim along with some personal user data, although no claim is mandatory.

There are several reserved claims as per JWT specification that are non mandatory but seven claims are recommended to have for better interoperability. The seven claims are as follows,

  • iss (issuer): party that issued the JWT
  • sub (subject): Identifies the user
  • aud (audience): Recipients of JWT or the application that reading the data from JWT
  • exp (expiration time): Time (seconds since epoch) after which the JWT expires
  • nbf (not before time): Time (seconds since epoch) from which JWT is considered as valid.
  • iat (issued at time): Time at which the JWT was issued
  • jti (JWT ID): Unique identifier; can be used to differentiate JWT from similar content.

You can see the complete list of reserved claims here.

Unencrypted JWTs

So far we have learned about the header and the payload part which is enough to construct a unencrypted JWT token.

Unencrypted JWTs formed with simple header

{
  "alg": "none",
  "typ": "JWT"
}

and with payload

{
  "sub": "user108",
  "name": "Shakal",
  "iat": 1629690269
}

now lets create a unencrypted JWT using these two parts. The pseudo code for this would be as follows,

token = base64urlEncode(header) + "." + base64urlEncode(payload) + "."

You can use any coding language to write encode and decode functions. Here I am using java 8 Base64 encoding that is part of JDK

import java.nio.charset.StandardCharsets;
import java.util.Base64;
public String base64urlEncode(String raw) {
    return Base64.getUrlEncoder().withoutPadding().encodeToString(raw.getBytes(StandardCharsets.UTF_8));
}

We also need to remove the trailing equal signs (=), for this we are using the withoutPadding() function. The resulting string will look like

ewogICJhbGciOiAibm9uZSIsCiAgInR5cCI6ICJKV1QiCn0.ewogICJzdWIiOiAidXNlcjEwOCIsCiAgIm5hbWUiOiAiU2hha2FsIiwKICAiaWF0IjogMTYyOTY5MDI2OQp9.

Conclusion

Now we have the basic understanding of structure of JWTs and different parts used to create JWTs. We discussed about the first two parts of JWT which is the header and the payload and created a unsecured JWT.
I real world scenarios, the use of unsecured JWTs is very rare or not at all.

In the next part, we will discuss about encrypted or secured JWTs and have more details on signature part.