DEV Community

Cover image for JWT for Developers: Behind the Scenes.
Andres Fernandez
Andres Fernandez

Posted on • Edited on

JWT for Developers: Behind the Scenes.

90% of developers just use the jsonwebtoken library without really understanding what’s happening behind the scenes. Be part of the percentage that does. Grab a coffee and enjoy the learning journey ☕🤯.

Technical definition JWT:

The Internet Engineering Task Force (IETF) is a globally recognized organization responsible for the creation and promotion of internet standards. In its document RFC 7519, the IETF defines JWT (JSON Web Tokens) as:

"A compact, URL-safe means of representing claims to be transferred between two parties. The claims in a JWT are encoded as a JSON object that is used as the payload of a JSON Web Signature (JWS) structure or as the plaintext of a JSON Web Encryption (JWE) structure, enabling the claims to be digitally signed or integrity protected with a Message Authentication Code (MAC) and/or encrypted."


Up to this point, we know the basics of JWTs ✅:

A JWT consists of three parts:

  • Header.
  • Payload.
  • Signature.

Library Trust: We trust that the jsonwebtoken library works well to keep our app secure.

Format: flow to get a JWT looks something like this:

Image


Uses of JWTs 🦾

JWTs signed with an algorithm and a secret key are known as JWS (JSON Web Signature). You have probably encountered them, and their use goes beyond merely assigning permissions for applications to access certain resources. Some of their most common uses include:

  • Authentication: Verifying the identity of a user.
  • Authorization: Granting or denying access to resources.
  • Federated Identity: Allowing multiple systems to share identity information.
  • Client-Side Sessions: Storing session information on the client side.
  • Client-Side Secrets: Keeping secrets on the client side without server storage.

Let's emphasize authorization. After the proper validation of a user's authentication, we need to assign a ticket for them to access certain protected resources of our applications.


JWT breakdown (Signed with SHA256 algorithm)

Image

We are going to focus on creating a signed JWT (JSON Web Token), commonly known as a JWT with a Signature, to establish secure communication between two parties that can validate its authenticity. There are two types of signed JWTs: the first is signed using the SHA algorithm, and the second is signed using the RSA algorithm (the latter will be covered in another guide).

Let's start building our JWT (Signature). We need a few things first.

  1. Function to convert JWT parts to Base64URL format ✔️.
  2. Secret Key ✔️.
  3. We use the native Node.js crypto module to sign it ✔️.

Why use Base64-URL?

This process ensures that the result is a valid text in URLs.

Convert binary data to Base64, Modify Special Characters, Replace + with -,Replace / with _, Remove any padding characters (=).

const crypto = require("crypto");

function base64urlEncode(data: string) {
  return Buffer.from(data)
    .toString("base64")
    .replace(/=/g, "")
    .replace(/\+/g, "-")
    .replace(/\//g, "_");
}
}
Enter fullscreen mode Exit fullscreen mode

Generate Secret Key 🔑

Now we will create our Secret Key, this must be stored securely, it is used to validate the signature, not to share. Avoid choosing short or obvious combinations. It is recommended to generate secure bytes like this one:

const crypto = require('crypto');

// Generate a 256-bit (32-character) secret key
const secretKey = crypto.randomBytes(32).toString('hex');
Enter fullscreen mode Exit fullscreen mode

Signature 🔏.

In this section, we explore the backbone of cybersecurity: cryptography!

The standard recommends using the HMAC function with SHA-256, known as HS256 in the JWA spec.

It also recommends RSA for tokens signed with private keys, a topic we will cover in another guide:

HMAC (Hash-based Message Authentication Code).

HMAC in Node.js uses a secret key and a hash function to create a unique code (MAC) that verifies the integrity and authenticity of a message. Here's a simplified explanation of what happens behind the scenes:

  1. Combine Key and Message: The secret key and the message are combined in a specific way.
  2. Apply Hash Function: This combination is then passed through a hash function (like SHA-256) twice.
  3. Generate Code: The result is a fixed-size code that is unique to the given message and key.

This code ensures that the message cannot be altered by a cybercriminal without invalidating the signature. If even a single bit in the message changes, the HMAC code will be different, indicating unauthorized tampering. In this way, HMAC protects against malicious modification attempts.

Function to create Signature 🛡️.


const crypto = require('crypto');


function createSignature(
  encodedHeader: string,
  encodedPayload: string,
  secret: string
) {
  const data = `${encodedHeader}.${encodedPayload}`;
  return crypto.createHmac("sha256", secret).update(data).digest("base64url");
}

Enter fullscreen mode Exit fullscreen mode

Graphical example of signature creation 🎨 🖌️.

box


Completed example

Here we have our completed example. As you can see, we can create our own token signing system. This is how libraries that use the JWT standard function. I encourage you to experiment with Node.js's Crypto module and implement your own solution.


const header = {
  alg: "HS256",
  typ: "JWT",
};

const payload = {
  sub: "1234567890",
  name: "John Doe",
  iat: Math.floor(Date.now() / 1000),
};

const encodedHeader = base64urlEncode(JSON.stringify(header));
const encodedPayload = base64urlEncode(JSON.stringify(payload));

const secret = "your-256-bit-secret";

function createSignature(
  encodedHeader: string,
  encodedPayload: string,
  secret: string
) {
  const data = `${encodedHeader}.${encodedPayload}`;
  return crypto.createHmac("sha256", secret).update(data).digest("base64url");
}

const signature = createSignature(encodedHeader, encodedPayload, secret);

const jwt = `${encodedHeader}.${encodedPayload}.${signature}`;

Enter fullscreen mode Exit fullscreen mode

Resume

The token signature is the result of passing the header, payload, and a secret through a hash function, obtaining a fixed value. This value acts as an impenetrable barrier for cybercriminals, ensuring that the data has not been modified and maintaining the integrity and authenticity of the information.

JWT(Signature) value
Integrity
Authenticity
Privacity

Remember 📌.

Not to include sensitive information in the payload of your JWTs, as they are only encoded, not encrypted. The JWT signature ensures the integrity and authenticity of the token but does not guarantee the privacy of the data.


Upcoming guides:

Best practices for creating your JWTs.
Validate JWTs like a pro.
Know the main attacks and common failures when implementing JWTs.

Top comments (1)

Collapse
 
jairofernandez profile image
Jairo Fernández

great!