What is a JWT?

A JWT is a compact, URL-safe token used for securely transmitting information between parties. It is an open standard (RFC 7519) that defines a method for representing claims securely between two parties. Claims in a JWT are encoded as a JSON object that is digitally signed using a cryptographic algorithm, ensuring that the claims cannot be altered after the token is issued.

JWTs are typically used in two main scenarios:

  • Authorization: Once the user logs in, each subsequent request will include the JWT, allowing the user to access routes, services, and resources that are permitted with that token. This is one of the most common uses of JWT today.
  • Information Exchange: JWTs are a good way to securely transmit information between parties. Because JWTs can be signed — for instance, using public/private key pairs — you can be sure that the senders are who they say they are. Additionally, the structure of a JWT allows you to verify that the content hasn't been tampered with.

JWT Structure

A JWT consists of three parts separated by dots (.). They are:

  1. Header: The header typically consists of two parts: the type of the token, which is JWT, and the signing algorithm being used, such as HMAC SHA256 or RSA. For example:

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

This JSON is Base64Url-encoded to form the first part of the JWT.

  1. Payload: The second part of the token is the payload, which contains the claims. Claims are statements about an entity (typically, the user) and additional metadata. There are three types of claims:
    • Registered claims: These are a set of predefined claims that are not mandatory but recommended. These include iss (issuer), exp (expiration time), sub (subject), and aud (audience).
    • Public claims: These can be defined by those using JWTs. However, to avoid collisions, these should be defined in the IANA JSON Web Token Registry or be defined as a URI.
    • Private claims: These are the custom claims created to share information between parties that agree on using them (e.g., user roles, permissions, etc.).

The payload is then Base64Url-encoded to form the second part of the JWT.

  1. Signature: To create the signature part, you have to take the encoded header, the encoded payload, a secret, and the algorithm specified in the header and sign that. For example, if you want to use the HMAC SHA256 algorithm, the signature will be created in the following way:

HMACSHA256(
  base64UrlEncode(header) + "." + base64UrlEncode(payload),
  secret
)
  

The signature is used to verify that the sender of the JWT is who it says it is and to ensure that the message wasn't changed along the way.

Thus, a JWT token looks like this:

xxxxx.yyyyy.zzzzz

How JWT Works

To understand how JWT works in practice, let's explore a common authentication flow in a web application that uses JWT for securing API calls.

  1. User Login: The user sends a login request to the server by providing credentials (username and password).
  2. JWT Creation: The server validates the credentials. If valid, it generates a JWT that contains claims, such as the user ID, and signs it using a secret key.
  3. JWT Transmission: The server responds with the JWT, and the client stores the token. This token is often stored in local storage or a cookie.
  4. Subsequent Requests: For every subsequent request, the client sends the JWT in the Authorization header:
Authorization: Bearer <token>
  1. JWT Verification: The server receives the request, extracts the JWT, and verifies its authenticity by checking the signature. If the token is valid and not expired, the server processes the request.

Benefits of Using JWT

There are several reasons why JWT has become so popular in modern applications:

  • Statelessness: JWT is stateless, meaning the server does not need to store session information. The token itself contains all the necessary data, making it ideal for horizontal scaling.
  • Compact and Efficient: JWTs are compact, making them easy to transmit between clients and servers, especially in environments like HTTP headers.
  • Self-contained: JWT contains all the information required for authentication and authorization within the token itself, reducing the need for repeated database lookups.
  • Cross-Domain Usage: JWT tokens are widely used for securing APIs, and they can be used in mobile applications, single-page applications (SPAs), and microservices environments.

JWT vs. Session-Based Authentication

Before JWT, session-based authentication was the norm for web applications. In session-based authentication, the server stores user sessions in memory or a database, and the client sends a session ID with each request. While this approach works well, it has certain limitations, especially in scaling distributed applications.

Here are the main differences between session-based and JWT-based authentication:

Session-Based Authentication JWT-Based Authentication
Requires server-side storage of session data. Stateless, no server-side session storage required.
Scalability can be challenging due to session data replication between servers. Highly scalable as the token contains all necessary information.
Session IDs are not self-contained and require database lookups. JWTs are self-contained, reducing the need for database lookups.

JWT Security Considerations

While JWT is a powerful tool, there are important security considerations to keep in mind:

  • Use Secure Algorithms: Always use strong cryptographic algorithms such as RS256 (RSA Signature with SHA-256) or HS256 (HMAC with SHA-256). Avoid using weak algorithms like none, as it can expose your application to attacks.
  • Keep Secrets Safe: The secret used to sign the JWT must be kept confidential. If an attacker gets hold of this secret, they can forge valid tokens.
  • Expiration Time: Always set an expiration time for your JWTs using the exp claim to prevent long-term validity. Tokens should be short-lived to reduce the window of attack in case they are compromised.
  • Token Storage: Do not store JWTs in places accessible by client-side scripts, such as local storage or session storage, as they are susceptible to cross-site scripting (XSS) attacks. Use HTTP-only cookies to mitigate this risk.
  • Token Revocation: JWTs are stateless, so revoking a token is not as simple as deleting a session on the server. One strategy to revoke tokens is to maintain a blacklist of invalid tokens or implement token rotation strategies.

Common Use Cases for JWT

JWTs are used in various applications, and some common use cases include:

  • API Authentication: JWTs are widely used in securing RESTful APIs. Each API call includes the JWT in the header, allowing the server to authenticate the request.
  • Single Sign-On (SSO): JWTs enable SSO across multiple systems by issuing a single token that can be validated by different services.
  • Microservices Authentication: In a microservices architecture, JWTs help secure communication between services. The token can be passed between services to ensure that only authorized requests are processed.
  • Mobile and SPA Authentication: JWTs are commonly used in mobile applications and SPAs (Single Page Applications) where session management is more complex. JWTs allow these apps to authenticate without relying on traditional cookies.

Conclusion

JWT has emerged as a widely adopted standard for securing web applications and APIs. Its stateless nature, self-contained structure, and cross-domain capabilities make it a preferred choice for many developers and organizations. However, while using JWT, it is crucial to adhere to security best practices, including strong encryption, short token lifetimes, and proper storage mechanisms.

Whether you're building a simple web application or a large-scale microservices architecture, understanding and implementing JWT properly can significantly enhance the security and scalability of your system.