JWTs: A Beginners Guide

In the world of modern web development, security is paramount. One of the key technologies that have gained immense popularity in recent years is JSON Web Tokens (JWTs). JWTs, pronounced "jot", have become a standard for securely transmitting information between parties in a compact, verifiable, and self-contained manner. In this article, we will delve into what JWTs are, how they work, and their various use cases in web development.

History of JWTs

The history of JSON Web Tokens (JWTs) is closely tied to the evolution of web development and the need for secure, stateless authentication mechanisms. The concept of JWTs began to take shape around the early 2000s as web developers sought more efficient ways to handle authentication and authorization in web applications.JWTs started to gain traction with the development of JSON (JavaScript Object Notation) as a lightweight data interchange format & the rise of token based authentication as an alternative to traditional session based authentication mechanisms.

The first draft of JWT is published on December 2010. The early draft states: “JSON Web Token (JWT) defines a token format that can encode claims transferred between two parties. The claims in a JWT are encoded as aJSONobject that is digitally signed.“. Numerous libraries, frameworks, and platforms emerged with built-in support for JWTs. This widespread adoption of JWTs has made it easier for developers to implement JWT-based authentication and authorization in their applications.

What is JWT ?

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. This information can be verified and trusted because it is digitally signed. JWTs can be signed using a secret (with the HMAC algorithm) or a public/private key pair using RSA or ECDSA.

JWT typically looks like this:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.
eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.
SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

Because of its relatively small size, a JWT can be sent through a URL, through a POST parameter, or inside an HTTP header, and it is transmitted quickly. A JWT contains all the required information about an entity to avoid querying a database more than once. The recipient of a JWT also does not need to call a server to validate the token.

Structure of JWT

A well-formed JWT consists of three concatenated Base64-URL encoded strings, separated by dots (.)

  • Header Contains metadata about the token, such as the type of token (JWT) and the signing algorithm used.

      {
        "alg": "HS256",
        "typ": "JWT"
      }
    
  • Payload contains the claims or information being transmitted. Claims are statements about an entity (typically, the user) and additional data. A claim appears as a name/value pair where the name is always a string and the value can be any JSON value.
    There are two types of JWT claims:

    1. Registered: standard claims registered with the Internet Assigned Numbers Authority (IANA) and defined by the JWT specification to ensure interoperability with third-party, or external, applications. OIDC standard claims are reserved claims.

    2. Custom: consists of non-registered public or private claims. Public claims are collision-resistant while private claims are subject to possible collisions

       {
          "sub": "1234567890",
          "name": "John Doe",
          "iat": 1516239022,
          "email": "ditlev.von.testesen@example.com",
          "exp": 1678382885
       }
      
  • Signature: The signature is generated by combining the encoded header, encoded payload, and a secret key using the specified algorithm. It ensures that the JWT has not been tampered with during transmission.

    The most common signing algorithms are

    • HMAC + SHA256

    • RSASSA-PKCS1-v1_5 + SHA256

    • ECDSA + P-256 + SHA256

  •   HMACSHA256(
        base64UrlEncode(header) + "." +
        base64UrlEncode(payload),
        your-256-bit-secret
      )
    

    You can use this fantastic jwt.io debugger to play around with JWT. It allows you to quickly check that a JWT is well formed and to manually inspect the values of the various claims.

How do JSON Web Tokens work?

In authentication, when the user successfully logs in using their credentials, a JSON Web Token will be returned. Since tokens are credentials, great care must be taken to prevent security issues. In general, you should not keep tokens longer than required.Whenever the user wants to access a protected route or resource, the user agent should send the JWT, typically in the Authorization header using the Bearer schema. The content of the header should look like the following:

Authorization: Bearer <token>

This can be, in certain cases, a stateless authorization mechanism. The server's protected routes will check for a valid JWT in the Authorization header, and if it's present, the user will be allowed to access protected resources

Use Cases of JWTs

  1. Authentication: JWTs are commonly used for user authentication in web applications. Once a user logs in and receives a JWT, they include it in subsequent requests to access protected resources.

  2. Single Sign-On (SSO): JWTs facilitate seamless SSO across multiple applications or services. Once authenticated in one application, the user can access others without re-entering credentials.

  3. Information Exchange: JWTs are used to securely transmit information between microservices in distributed architectures. Each microservice can validate the JWT and extract necessary information.

  4. Stateless Sessions: Unlike traditional session-based authentication, JWTs enable stateless sessions where the server does not need to store session data. This scalability is beneficial in large-scale applications.

Best Practices for Using JWTs

  1. Use Strong Secret Keys: Ensure that the secret key used to sign JWTs is sufficiently long and random to prevent brute force attacks.

  2. Set Expiration Time: Include an expiration time (exp) in the JWT to limit its validity period and reduce the risk of token misuse.

  3. Validate and Verify: Always validate the JWT signature and verify the claims before trusting the information contained within the token.

  4. Avoid Storing Sensitive Information: a successfully validated token only means that the information contained within the token has not been modified by anyone else. This doesn't mean that others weren't able to see the content, which is stored in plain text. Because of this, you should never store sensitive information inside a JWT. Store such data securely on the server side.

Pros of JWTs

  • More compact: JSON is less verbose than XML, so when it is encoded, a JWT is smaller than a SAML token. This makes JWT a good choice to be passed in HTML and HTTP environments.

  • More secure: JWTs can use a public/private key pair in the form of an X.509 certificate for signing. A JWT can also be symmetrically signed by a shared secret using the HMAC algorithm. And while SAML tokens can use public/private key pairs like JWT, signing XML with XML Digital Signature without introducing obscure security holes is very difficult when compared to the simplicity of signing JSON.

  • More Common: JSON parsers are common in most programming languages because they map directly to objects. Conversely, XML doesn't have a natural document-to-object mapping. This makes it easier to work with JWT than SAML assertions.

  • Easier to process: JWT is used at internet scale. This means that it is easier to process on users' devices, especially mobile.

Cons of JWTs

  • Size: JWTs can be larger than other types of tokens, especially if they carry a lot of information in their payload.

  • Statelessness: if you need to invalidate a JWT before its expiration time, it can be challenging because JWTs are designed to be self-contained and stateless.

  • Security Concerns: JWTs, if not implemented correctly, can be susceptible to certain security vulnerabilities such as token leakage, replay attacks, and token tampering

  • Revocation: Unlike traditional session tokens, JWTs are not easily revocable. Once issued, a JWT remains valid until it expires or is explicitly invalidated by changing the key used for signing.

JWT Libraries

JWT.IO provides several language specific libraries for token signing and verifications. You can check out the available libraries here. Lets see the Node.js jwt library jsonwebtoken in action here:

const jwt = require('jsonwebtoken');

// Secret key used for signing and verifying the JWT
const SECRET_KEY = 'mysecretkey';

// Example payload
const payload = {
  userId: '123456',
  username: 'john_doe',
};

// Sign the JWT
const token = jwt.sign(payload, SECRET_KEY, { algorithm: 'HS256', expiresIn: '1h' });

console.log('Generated JWT:', token);

// Verify the JWT
jwt.verify(token, SECRET_KEY, (err, decoded) => {
  if (err) {
    console.error('JWT verification failed:', err.message);
  } else {
    console.log('Decoded JWT:', decoded);
  }
});

Conclusion

JSON Web Tokens (JWTs) are a powerful tool for secure authentication, authorization, and information exchange. By understanding the structure, working principles, and best practices of JWTs, developers can leverage this technology effectively to enhance the security and functionality of their applications.

In summary, JWTs provide a standardized, efficient, and secure way to transmit information between parties, making them a cornerstone of modern web security architecture.