Learnitweb

JSON Web Token (JWT) – An Introduction

1. Introduction

JSON Web Token (JWT) is a lightweight, compact, and URL-safe way to represent a set of claims between two parties. It’s especially useful in environments where bandwidth or storage is limited, such as:

  • HTTP Authorization headers
  • URI query parameters

JWTs are typically used in web authentication and authorization flows. They allow claims (such as user identity or roles) to be transmitted as a JSON object. These claims can then be:

  • Signed, using a JSON Web Signature (JWS) for integrity and authenticity.
  • Encrypted, using a JSON Web Encryption (JWE) for confidentiality.
  • Or both (nested encryption and signing).

In all cases, JWTs use the Compact Serialization format, which represents the JWT as a single string composed of three (or more) parts, separated by dots (.).

Pronunciation: JWT is pronounced as “jot”, like the English word.


1.1. Notational Conventions

In this tutorial, terms like “MUST”, “SHOULD”, and “MAY” are used to describe implementation requirements. These terms are based on RFC 2119, which standardizes how requirements are described in technical documentation:

  • MUST: This is an absolute requirement.
  • SHOULD: Strongly recommended, but there may be valid reasons to ignore.
  • MAY: Optional, based on implementation or context.

These keywords only apply when written in UPPERCASE.


2. Terminology

To understand JWT clearly, it’s important to get familiar with some foundational terms. These terms are either defined in related specifications (JWS, JWE) or directly within this specification.

Terms from Related Specifications

  • JSON Web Signature (JWS): A way to sign data using cryptographic algorithms.
  • Base64url Encoding: A URL-safe variant of Base64 encoding without padding.
  • JOSE Header: JSON metadata indicating how the JWT is signed/encrypted.
  • JWS Compact Serialization: Compact format for JWS; used in JWT.
  • JWE Compact Serialization: Compact format for JWE; used for encrypted JWTs.
  • JWE Encrypted Key: The encrypted symmetric key used to encrypt the payload.
  • JWE Initialization Vector: Random value used in encryption.
  • Ciphertext / MAC / Plaintext: Cryptography-related terms (as per RFC 4949).

Terms Defined in JWT Specification

  • JWT (JSON Web Token): A string that represents a set of claims. It is digitally signed (JWS), encrypted (JWE), or both. It is always a Base64url-encoded string divided into sections using periods (.).
  • JWT Claims Set: The actual payload of the JWT. It is a JSON object that contains all claims about a user or system.
  • Claim: A statement about a subject (user, entity, etc.), expressed as a key-value pair.
  • Claim Name: The key in the claim pair. Always a string.
  • Claim Value: The value associated with the claim name. It can be any valid JSON type: string, number, boolean, object, or array.
  • Nested JWT: A JWT used as a payload inside another JWT. This allows for both signing and encryption in layers — for example, sign first, then encrypt.
  • Unsecured JWT: A JWT that is not signed or encrypted. It uses "alg": "none" in the header and provides no integrity or confidentiality guarantees.
  • Collision-Resistant Name: A unique identifier designed to avoid conflicts. Examples include:
    • Domain names (e.g., example.com)
    • UUIDs
    • Object Identifiers (OIDs)
  • StringOrURI: A string that may be arbitrary, but if it contains a colon (:), it must be a valid URI (e.g., http://example.com).
  • NumericDate: A numeric timestamp representing the number of seconds since Unix epoch (1970-01-01T00:00:00Z). It ignores leap seconds and aligns with POSIX time.

3. JWT Overview

At a high level, a JWT consists of claims in the form of a JSON object. This JSON object is called the JWT Claims Set. These claims are either:

  • Signed (JWS) for data integrity.
  • Encrypted (JWE) for confidentiality.
  • Both (nested).

A JWT is composed of Base64url-encoded components, separated by periods (.):

<Header>.<Payload>.<Signature>

Here’s what each part represents:

  • Header: Contains metadata such as the signing algorithm and type.
  • Payload: The claims data (like user ID, expiration time).
  • Signature: The cryptographic signature (for signed tokens only).

The JOSE Header describes what algorithm and key information was used. Depending on the type (JWS or JWE):

  • If JWS: The claims are digitally signed (MACed). The payload is visible but protected from tampering.
  • If JWE: The claims are encrypted. The payload is hidden from unauthorized parties.

You can also wrap a JWT in another JWT to support nested operations: for example, first sign the payload, then encrypt the entire signed JWT.

Compact Representation

A JWT is a single string, using Compact Serialization format:

  • URL-safe
  • Dot-separated (.)
  • Base64url-encoded components

The number of parts depends on whether it’s a JWS or JWE.


3.1. Example JWT

Let’s walk through an example of a signed JWT using HMAC SHA-256.

Header (JOSE Header)

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

This header declares that:

  • The type is JWT.
  • The signing algorithm is HMAC with SHA-256.

UTF-8 bytes of the header:

[123, 34, 116, 121, 112, 34, 58, 34, 74, 87, 84, 34, 44, 13, 10, 32,
34, 97, 108, 103, 34, 58, 34, 72, 83, 50, 53, 54, 34, 125]

Base64url-encoded result:

eyJ0eXAiOiJKV1QiLA0KICJhbGciOiJIUzI1NiJ9

Payload (JWT Claims Set)

{
  "iss": "joe",
  "exp": 1300819380,
  "http://example.com/is_root": true
}

This payload contains:

  • iss: Issuer (joe)
  • exp: Expiration timestamp
  • Custom claim: whether user is a root user

UTF-8 bytes:

[123, 34, 105, 115, 115, 34, 58, 34, 106, 111, 101, 34, 44, 13, 10,
32, 34, 101, 120, 112, 34, 58, 49, 51, 48, 48, 56, 49, 57, 51, 56,
48, 44, 13, 10, 32, 34, 104, 116, 116, 112, 58, 47, 47, 101, 120, 97,
109, 112, 108, 101, 46, 99, 111, 109, 47, 105, 115, 95, 114, 111,
111, 116, 34, 58, 116, 114, 117, 101, 125]

Base64url-encoded payload:

eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ

Signature

Using the HMAC SHA-256 algorithm and a secret key, we compute the MAC over:

<base64url-header> + "." + <base64url-payload>

The result is base64url-encoded and produces:

dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk

Final JWT

Joining all parts with .:

eyJ0eXAiOiJKV1QiLA0KICJhbGciOiJIUzI1NiJ9
.
eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ
.
dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk

This JWT is a self-contained token that can be transmitted securely over HTTP. The recipient can verify the signature and decode the payload to access the claims.