DevAtlas

Learn

  • Dashboard
  • Learning Paths
  • All Categories
  • Topics

Practice

  • Interview Questions
  • Flashcards
  • Quizzes
  • Study Plans

Personal

  • Bookmarks
  • Notes
  • Progress
  • PDF Library
  • Settings
  • About
  1. Topics
  2. JWT (JSON Web Tokens)
0%
Authentication and Authorization

JWT (JSON Web Tokens)

A JWT is a compact, signed token that carries claims about a user. Learn its three parts, why it is signed but not encrypted, and how to use it safely.

Intermediate25 min study11 min read
Export PDF

Prerequisites: Authentication vs Authorization

Learning objectives

  • Break a JWT into its three Base64URL parts: header, payload, and signature.
  • Explain that a JWT is signed for integrity and authenticity, not encrypted for secrecy.
  • Identify the standard registered claims (iss, sub, aud, exp, iat, nbf) and when to use custom claims.
  • Recognize common JWT pitfalls (alg:none, weak secrets, no expiry, unsafe storage) and how to avoid them.

Simple explanation

Think of a JWT like a festival wristband. When you buy a ticket at the gate, staff give you a wristband that says who you are and which areas you can enter. From then on you don't queue at the ticket office again — you just show the wristband and security waves you through. The wristband is *tamper-evident*: it has a special seal so nobody can fake one or change what's printed on it without it being obvious.

A JWT (JSON Web Token) works the same way. After you log in, the server hands you a signed token. On every later request you present that token, and the server trusts it — because the signature proves the server itself issued it and nobody altered it.

Technical explanation

A JWT is a single string with three parts separated by dots:

code
header.payload.signature

Each part is Base64URL-encoded (not encrypted — just encoded, so anyone can decode it).

  1. Header — a small JSON object describing the token, mainly the signing algorithm (alg, e.g. HS256 or RS256) and the type (typ: "JWT").
  2. Payload — a JSON object holding the claims: statements about the user and the token. *Registered* claims are standardized short names:
  • iss (issuer), sub (subject — usually the user id), aud (audience),
  • exp (expiration time), iat (issued at), nbf (not valid before).

You can also add your own custom claims like role or email.

  1. Signature — the security guarantee. The server takes base64url(header) + "." + base64url(payload) and signs it, either with a shared secret (HMAC, e.g. HS256) or a private key (RSA/ECDSA, e.g. RS256/ES256). On each request the server recomputes the signature and checks it matches.

The critical property: a JWT is signed, not encrypted. Signing protects integrity (the payload wasn't changed) and authenticity (a trusted party issued it). It does *not* hide the contents. Anyone who holds the token can Base64URL-decode the payload and read every claim.

Why it matters

JWTs enable stateless authentication. Because the token is self-contained — it carries the user id, roles, and expiry inside it — the server can verify a request just by checking the signature, without a database or session-store lookup. That makes horizontal scaling easy: any server instance can validate any token. This is why JWTs are the backbone of most modern APIs, single sign-on (SSO), and microservice-to-microservice auth.

How it works

A typical login-then-request flow:

  1. The user logs in with credentials; the server verifies them.
  2. The server builds a payload (sub, exp, custom claims) and signs it, producing the JWT.
  3. The token is sent to the client, which stores it (ideally an httpOnly cookie).
  4. On each subsequent request the client sends the token, usually as Authorization: Bearer <token>.
  5. The server verifies the signature and checks exp/nbf/aud. If valid, it trusts the claims and processes the request — no session lookup needed.
  6. When the token expires, the client obtains a new one (typically via a refresh token).

Real-world analogy

A JWT is like a sealed, signed concert ticket. Anyone can read what's printed on it — your seat, the date, your name — so you would never write your credit-card PIN on the ticket. But the venue's official seal (the signature) means the gate can instantly tell a genuine ticket from a forgery, without phoning head office (no database call). If someone tries to erase "balcony" and write "front row", the seal breaks and the ticket is rejected. And every ticket has a date on it (exp) so an old one won't get you in next year.

Important terminology

  • Claim — a single statement inside the payload, e.g. "sub": "user_42" or "role": "admin".
  • Signature — a cryptographic value over the header and payload that proves integrity and authenticity.
  • HMAC vs RSA/ECDSA — HMAC (HS256) uses one shared secret for both signing and verifying; RSA/ECDSA (RS256/ES256) uses a private key to sign and a public key to verify, which is better when many parties must verify but only one issues.
  • Stateless — the server stores no session; everything needed to authorize the request lives in the token itself.
  • Bearer token — whoever *bears* (holds) the token can use it, which is exactly why transport (HTTPS) and safe storage matter.

Key definitions

Token
The compact header.payload.signature string a client presents to prove who it is on each request.
Claim
A single statement inside the payload, such as sub (subject), exp (expiry), or a custom role.
Signature
A cryptographic value over the header and payload that proves the token was not tampered with and was issued by a trusted party.
Statelessness
The server keeps no session; the self-contained token carries everything needed to authorize a request.

Must memorize

Must memorize

  • A JWT has three Base64URL parts: header.payload.signature.
  • A JWT is signed, not encrypted — anyone can read the payload, so never put secrets in it.
  • The signature proves integrity and authenticity; it does not hide the contents.
  • JWTs are hard to revoke — use short exp and a refresh-token flow.

Real-world example

Stateless API authentication

A React app logs the user in and receives a JWT. It sends the token as "Authorization: Bearer <token>" on every API call. Each backend instance verifies the signature and reads the sub and role claims to authorize the request — with no shared session store, so the API scales horizontally without sticky sessions.

Single sign-on (SSO) with RS256

An identity provider signs tokens with its private key. Many independent services verify those tokens using the provider’s public key (fetched via JWKS). Only the provider can issue tokens, but every service can verify them offline — a perfect fit for asymmetric (RS256/ES256) signing.

Code example

decoded-jwt.json
// The token on the wire (three dot-separated Base64URL parts):
// eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VyXzQyIiwicm9sZSI6ImFkbWluIiwiaWF0IjoxNzM2NTAwMDAwLCJleHAiOjE3MzY1MDM2MDB9.3xq9...signature

// 1) header  -> describes the signing algorithm
{
  "alg": "HS256",
  "typ": "JWT"
}

// 2) payload -> the claims (registered + custom). NOT secret!
{
  "sub": "user_42",      // subject: the user id
  "role": "admin",       // custom claim
  "iss": "api.devatlas", // issuer
  "iat": 1736500000,     // issued at (unix seconds)
  "exp": 1736503600      // expires 1 hour later
}

The header and payload of a decoded JWT. Both are just Base64URL-encoded JSON — readable by anyone.

sign.js
import jwt from 'jsonwebtoken';

const SECRET = process.env.JWT_SECRET; // long, high-entropy, never in source

// Sign a token. exp is set via expiresIn; iat is added automatically.
const token = jwt.sign(
  { sub: 'user_42', role: 'admin' }, // custom + subject claims
  SECRET,
  { algorithm: 'HS256', expiresIn: '1h', issuer: 'api.devatlas' },
);

console.log(token); // eyJhbGci...

Signing a JWT in Node with the jsonwebtoken library.

verify.js
import jwt from 'jsonwebtoken';

const SECRET = process.env.JWT_SECRET;

try {
  // Pinning algorithms prevents the alg:none / algorithm-confusion attack.
  const payload = jwt.verify(token, SECRET, {
    algorithms: ['HS256'],   // never trust the token's own alg header blindly
    issuer: 'api.devatlas',
  });

  // Signature + exp + iss are valid; we can trust the claims.
  console.log(payload.sub, payload.role); // 'user_42' 'admin'
} catch (err) {
  // TokenExpiredError, JsonWebTokenError (bad signature), etc.
  console.error('Invalid token:', err.message);
}

Verifying a JWT safely: pin the algorithm and check the issuer.

Common mistakes

Mistake

Storing sensitive data (passwords, full card numbers, secrets) in the JWT payload.

Do this instead

The payload is only Base64URL-encoded, so anyone can read it. Put only non-secret claims (ids, roles, expiry) in it.

Mistake

Trusting the alg field from the token and accepting alg:none or a weak secret.

Do this instead

Pin the expected algorithm server-side, reject "none", and use a long, high-entropy secret (or asymmetric keys).

Interview questions

Quiz

Question 1 of 40 ✓
What are the three parts of a JWT, in order?
Select an answer to continue.

Flashcards

Card 1 of 3

Show answer · Space

Summary

A JWT is a compact, self-contained token made of three Base64URL parts — header, payload, and signature. The signature (HMAC or RSA/ECDSA over header+payload) guarantees integrity and authenticity, which enables stateless authentication. Crucially, a JWT is signed, not encrypted: anyone can read the payload, so never store secrets in it. Guard against alg:none, weak secrets, and missing expiry, prefer httpOnly cookies over localStorage, and pair short-lived tokens with refresh tokens because JWTs are hard to revoke.

References

  • jwt.io — Introduction to JSON Web Tokens
  • RFC 7519 — JSON Web Token (JWT)

Related topics

Authentication vs AuthorizationAccess Tokens and Refresh Tokens
Previous
Authentication vs Authorization
Next
Access Tokens and Refresh Tokens

On this page

  • Learning objectives
  • Simple explanation
  • Technical explanation
  • Why it matters
  • How it works
  • Real-world analogy
  • Important terminology
  • Key definitions
  • Must memorize
  • Real-world example
  • Code example
  • Common mistakes
  • Interview questions
  • Quiz
  • Flashcards
  • Summary