Dec 16, 2022

Working with JSON Web Tokens in Node.js

Working with JSON Web Tokens in Node.js

A JSON Web Token often abbreviated JWT (pronounced "jot") is a compact, self-contained and digitally signed token, that uses the JSON format to transmit information between parties.

Beyond its encryption method, what makes it popular is the use of the JSON format, that's way more compact than XML for example, which makes it easier to manipulate for the web and generally easier to use, as JSON parsers are quite common in most programming languages.

In this article, you'll learn how sign and decode JSON web tokens in Node.js using the jsonwebtoken package.

Anatomy of the JWT

A JWT is composed of three parts: the header, the payload and the signature, where each part is separated by a dot character.

header.payload.signature

JWT Header

The header is a Base64Url encoded object consisting of two fields: the type of token and the signing algorithm.

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

JWT Payload

The payload is also a Base64Url encoded object containing pieces of information about an entity (usually a user), and additional data called claims, that can be of three types:

  • Registered claims are non-mandatory pre-defined claims that can be specified to ensure interoperability with third-party or external applications such as the issuer of the token or its expiration time.
  • Public claims are usually generic non-sensitive information such as a user full name or an email address.
  • Private claims are usually application specific and sensitive information such as an internal user ID.
{
  "exp": 1638298179,            // registered
  "name": "John Doe",           // public
  "email": "johndoe@mail.net",  // public
  "internal_id": "admin1234"    // private
}

JWT Signature

Finally, the signature is created by using a combination of the algorithm specified in the header, a secret value, and the dot concatenated value of the encoded header and payload.

HmacSHA256(
  secret,
  base64url(header) + '.' + base64url(payload)
)

The jsonwebtoken package

The most popular package for manipulating JWTs in Node.js is jsonwebtoken and can be installed using the following command:

$ npm install --save jsonwebtoken

Signing a new JWT

To generate (i.e. sign) a new JSON web token, we can use the top-level sign() method, which takes three arguments:

  • A payload, which is the data we want to send to the client (e.g. the user ID).
  • A secret or a private key, which is either a string of characters (e.g. "myJWTSecret") or a PEM file that can be generated using a tool such as ssh-keygen.
  • A non-mandatory options object, which contains additional or meta data such as the algorithm, the expiration date or the issuer of the token (c.f. claims).
const jwt = require('jsonwebtoken');

const payload = {
  name: "John"
};
const secret = "mysecret";
const token = jwt.sign(payload, secret);

console.log(token);

Running the above script, will produce the following output:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoiSm9obiIsImlhdCI6MTY1OTAwODQxMH0.w-z_Ht5B4PLQFUQJhymbERqudUboCVtmM24t2y-UjsE

Defining an expiration date

Every piece of information that goes through networks such as the Internet can potentially be stolen. For this reason, it is usually recommended to define an expiration date to a JWT, so that, a stolen token does not grant an attacker infinite access to a protected resource.

The first method consists in defining an exp claim in the payload object, that contains the number of seconds until the expiration date, since the Epoch (January 01, 1970).

const jwt = require('jsonwebtoken');

const payload = {
  name: "John",
  exp: Math.floor(Date.now() / 1000) + (60 * 60)  // 1h
};
const secret = "mysecret";
const token = jwt.sign(payload, secret);

The second method consists in adding an expiresIn field on the options object, that contains a string of characters describing a time span.

const jwt = require('jsonwebtoken');

const payload = {
  name: "John"
};
const secret = "mysecret";
const options = {
  expiresIn: "1h"
};
const token = jwt.sign(payload, secret, options);

Decoding a JWT

To decode a JSON web token, we can use the top-level verify() method exported by the module, which takes three arguments:

  • A token, which is the JSON web token to decode.
  • A secret or a public key, which is either a string of characters (e.g. "myJWTSecret") or a PEM file that can be generated using a tool such as ssh-keygen.
  • A non-mandatory options object to perform additional token verifications.
const jwt = require('jsonwebtoken');

const token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoiSm9obiIsImlhdCI6MTY1OTAwODQxMH0.w-z_Ht5B4PLQFUQJhymbERqudUboCVtmM24t2y-UjsE";
const secret = "mysecret";
const payload = jwt.decode(token, secret);

console.log(payload);

Running the above script, will produce the following output:

{ name: 'John', iat: 1659008410 }

Related posts