A comprehensive guide to JSON Web Tokens (JWT)

tech
backend
security
jwt
json
web
tokens

Before we dive into the details of JWT, let’s understand what JWT is and why it is used.

What is JWT?

JWT stands for JSON Web Token. It is a standard way to represent tokens. JSON tokens are a lightweight mechanism to share information between two parties. It is popularly used to authenticate users and allow them to access protected resources.

What does JWT look like?

JWT is just a data format. It is made up of three parts:

1. Header

Header specifies the token type and the signing algorithm.

2. Payload

Payload contains the claims. Claims are statements about an entity (e.g. user) and additional metadata about the user.

3. Signature

Signature is the part that is signed using the secret key. It is used to verify the token and ensure that it is not tampered with. Two popular algorithms for signing are HMAC+SHA256 and RSA+SHA256. We will discuss further in the article.

Note:

  1. JWT is not encrypted typically. That means anyone can read the data inside.

How does Authentication using JWT work?

JWT Authentication Flow

  1. User logs in with their credentials.
  2. If the credentials are valid, the server generates a access token and a refresh token.
  3. Access Token is sent whenever a request is made to access a protected resource

Access Token

  1. Access token is a JWT token that contains the user’s information.
  2. You can add any information that is particular to the user’s authentication. Typically, it contains the user information (eg. id, email, name, etc) and some information about the authorization (eg. organization, role, etc). If your application requires more information to identify the user, you can add that to the payload.
  3. Access token is short-lived. It is typically set to expire in minutes (eg. 30 minutes).
  4. Before the access token expires, the user can use the refresh token to get a new access token.

How does refresh token work?

There are two ways to generate a new access token (from the client side):

  1. Let the user login again. This is not a good user experience for most applications. However, highly secure applications eg. banking applications use this approach.
  2. Use the refresh token to silently refresh the access token (without explicitly asking the user)
  3. Refresh tokens are long-lived. They are typically set to expire in days (eg. 1 day to 7 days).

Here is a simple sequence diagram to explain how refresh tokens work. JWT Refresh Token Flow

When to do the silent refresh flow?

  1. Whenever the user opens the application, the first request could be a silent refresh to fetch a new access token.
  2. At a set interval (eg. before 10 minutes of expiry of the access token), silent refresh flow can be done.
  3. You can also trigger the silent refresh if the server returns forbidden error (403) due to expired access token.

Let’s talk about the client side implementation

Where do we store the tokens?

This is a very important, but often overlooked question. Client side web applications are vulnerable to many attacks and storing tokens correctly is crucial.

Let’s look at two common attacks:

  1. Cross-Site Scripting (XSS) XSS is a type of attack where the attacker injects malicious scripts into the web page. These scripts can be used to steal the token from the client side. To prevent XSS attacks, the client side JavaScript code should not be able to access the token.

Note: Local Storage can be easily accessed by the client side JavaScript and is vulnerable to XSS attacks.

  1. Cross-Site Request Forgery (CSRF) CSRF is a type of attack where the attacker forces the user to make a request to the application. This can be done by tricking the user to click on a malicious link or embedding a malicious script in the web page.

Note: Cookies are vulnerable to CSRF attacks.

One way to store the tokens is to store them in a “HttpOnly” cookie. This is a special type of cookie that prevents the client side JavaScript from accessing it (preventing XSS attacks). Additonally, the cookie can have the following attributes:

  1. Secure: This attribute ensures that the cookie is only sent over HTTPS connections.
  2. SameSite: This attribute prevents the cookie from being sent along with requests to other sites.

Other considerations

  1. Refresh tokens cookies should not be sent with every request. This can open up to man-in-middle attacks (A man-in-the-middle attack is a type of attack where the attacker intercepts the communication between two parties). Instead, you can design an API with the path /refresh-token to fetch a new access token (and a new refresh token) by sending a valid refresh token cookie.

What are the advantages of using JWT?

  1. Stateless Authentication: JWT is stateless and does not require a server to maintain a session state. You can avoid storing the tokens in the server side database.
  2. Flexibility: JWT can have a custom paylod along with the user’s information. This can reduce multiple requests to the server. Eg. User’s organization information can be added to the JWT token.
  3. Cross Domain: JWT can be used across different servers especially in microservices architecture. Just pass the JWT token to the other services to access the protected resources.

FAQs

Which algorithm to use while signing the JWT token?

There are two common algorithms:

HMAC + SHA256 (most applications can use this)

  • This is a symmetric algorithm. The same secret key is used for signing and verifying the token.
  • The secret key should be well hidden and stored securely on the server side.
  • This is an asymmetric algorithm. A public key is used for signing the token and a private key is used for verifying the token.
  • The public key can be distributed to multiple different servers, so they can verify the token.
  • Only the auth server stores the private key and can create the token.

How can I revoke a JWT token?

Since JWT is stateless, this requires a new feature implementation. One approach is to store a blacklist of revoked tokens in the server side database. You can even use in-memory databases like Redis to store the blacklists.

What validations should be done on the server side while verifying the JWT token?

  1. After verifying the signature, check if the token has expired.
  2. (If implemented) Check if the token is already revoked.
  3. Verify the issuer of the token (in the payload i.e. iss field), if it is set.
  4. Verify the audience of the token (in the payload i.e. aud field), if it is set.
  5. Based on the user payload, check if the user has access to the protected resource or not.

Let me know if you have any questions or feedback.

Comments

Sharath 11:09 AM @ 4/3/2025
Really loved the article! It clearly communicates the idea.
Admin 11:43 AM @ 4/3/2025
Thank you Sharath. Glad it was helpful.