Have you ever noticed that some websites have a private section that requires a username and password to access? You might also have noticed that, once logged in, you’re often not asked to re-enter your username and password for subsequent visits. In stateless web applications, this behavior is achievable by using a JWT token. JWT, which stands for JSON Web Token, is a data exchange standard defined by RFC7519 in 2015.

In simple terms, a JWT token allows a user to communicate their identity to a REST application without needing to enter a username and password each time.

Structure of the Token

A JWT token consists of three main components:

  • Header: Contains information about the type of token and the signing algorithm used.
  • Payload: Contains all the information exchanged between the user and the application.
  • Signature: Represents the encoding of the previous two sections and is encrypted using a secret key.

JWT Token: An Example

To see what a JWT looks like, you can visit jwt.io. Here’s an example of a token structure:

  • Header
{
  "alg": "HS256",
  "typ": "JWT"
}
  • Payload
{
  "sub": "1234567890",
  "name": "John Doe",
  "iat": 1516239022
}
  • Signature
HMACSHA256(
  base64UrlEncode(header) + "." +
  base64UrlEncode(payload),
  your-256-bit-secret
)

The result is:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

You can distinguish the three components, as they’re separated by a “.”

Customizing the JWT Token

JWT tokens can be customized using Claims. Claims are a map of values representing information useful for the application. These are placed within the Payload and contribute to the token’s overall size.

Here’s an example of a customized Payload:

{
  "sub": "johndoe@test.com",
  "firstName": "John",
  "lastName": "Doe",
  "iat": 1728830222,
  "exp": 1728866222
}

The resulting token will look like:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJqb2huZG9lQHRlc3QuY29tIiwiZmlyc3ROYW1lIjoiSm9obiIsImxhc3ROYW1lIjoiRG9lIiwiaWF0IjoxNzI4ODMwMjIyLCJleHAiOjE3Mjg4NjYyMjJ9.OYqR8KbYa0n6-Zrx1SQKXZAeX4a2iO6xZKrkC2_wLwQ

What Not to Do!

Now that we understand what a JWT token is and how it can be customized, let’s look at a common security mistake. Imagine you have APIs protected by JWT, accessible only to users with a specific role. Here’s an example of a JWT Payload for an admin user:

{
  "sub": "johndoe@test.com",
  "firstName": "John",
  "lastName": "Doe",
  "role": "ADMIN",
  "iat": 1728830222,
  "exp": 1728866222
}

With this token, our application identifies “John Doe” and grants access to admin-only APIs. But what if John Doe were actually a regular user (with role “USER”) and manually changed his role? The result would be a valid token that allows unauthorized access to protected APIs.

This problem can be addressed in two ways:

  1. Avoid placing sensitive attributes like roles within the token.
  2. If unavoidable, ensure these attributes are validated against your app’s database.

Conclusion

JWT tokens are a popular standard for authorizations in web applications. For further details, refer to this link. Have you used JWT tokens in your applications? Let us know in the comments!