Skip to content

Intermediate · Authentication and authorization · topic 33 of 54 · 30 min

JSON Web Tokens (JWT)

Explanation

A JWT is a signed token that carries facts about a user, such as their id and when the token expires. The server can check the signature without looking anything up in a database. Anyone can read a JWT, so never put secrets in it, and always verify the signature before trusting it.

What a JWT looks like

A JWT (JSON Web Token, said "jot") is three pieces of text joined by dots: header.payload.signature. The header says how it was signed. The payload holds claims, which are facts like "user 42, expires at 10:15". The signature proves the server made it and nobody changed it.

output
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9      <- header  {"alg":"HS256","typ":"JWT"}
.
eyJzdWIiOiI0MiIsIm5hbWUiOiJBc2hhIiwiZXhwIjoxOTAwMDAwMDAwfQ
                                          <- payload {"sub":"42","name":"Asha","exp":1900000000}
.
v-5a3JP0uhw6kTBBLn0jq7yvz6nFx2PctEvhWBfF56A <- signature (HMAC-SHA256)
A real JWT split into its three parts.
Think of it like this: A JWT is like a festival wristband with a hologram. Anyone can read the name and date printed on it. The guard does not phone the office; he checks the hologram. If someone edits the date, the hologram no longer matches and the band is rejected.

base64url: encoding, not hiding

Each part is base64url encoded. Base64 turns bytes into letters, digits and a few symbols; the "url" version uses - and _ instead of + and / and drops the = padding, so the token is safe in URLs. Encoding is not encryption: anyone can decode the payload in one line.

Common claims

ClaimMeaningExample
subSubject: who the token is about (user id)"42"
expExpiry time, in seconds since 1 Jan 19701900000000
iatIssued at, in seconds1899999100
issIssuer: who made it"https://auth.myshop.in"
audAudience: who it is meant for"myshop-api"

Signing: HS256 or RS256

HS256RS256 / ES256
KeysOne shared secret signs and verifiesPrivate key signs, public key verifies
Good forOne backend that both makes and checks tokensMany services, or tokens from a login provider like Google
RiskEvery service with the secret can also create tokensOnly the private key holder can create tokens
javascript
// Example only: runs on a server with Node.js and the jose package
import { SignJWT, jwtVerify } from 'jose';
const secret = new TextEncoder().encode(process.env.JWT_SECRET);

const token = await new SignJWT({ role: 'customer' })
  .setProtectedHeader({ alg: 'HS256' })
  .setSubject('42')
  .setIssuedAt()
  .setExpirationTime('15m')
  .sign(secret);

// Verify checks the signature AND exp; pin the allowed algorithm
const { payload } = await jwtVerify(token, secret, { algorithms: ['HS256'] });
Use a well-tested library such as jose to create and verify JWTs.
Careful: Decoding is not verifying. Never trust a JWT until its signature and exp are checked. Pin the algorithm you expect, and reject tokens with "alg": "none".

Short life, refresh tokens and storage

Keep access tokens short-lived (5 to 15 minutes). A refresh token is a second, long-lived token used only to get a new access token. Store refresh tokens on the server so you can cancel them, and rotate them (give a new one each time).

In a browser, keep tokens in an HttpOnly, Secure, SameSite cookie rather than localStorage, because any XSS bug can read localStorage. Mobile apps use the phone's secure storage (Keychain or Keystore).

Logging out a JWT

A JWT stays valid until exp, even after the user presses logout, because the server does not look it up. To block one early you need a denylist: store its id (the jti claim) until it would expire, and check that list on each request. In practice: short expiry plus deleting the refresh token.

Careful: Never put passwords, OTPs, card numbers or other private data in the payload. Anyone who holds the token can read it.
Tip: For a normal website, server sessions are often simpler and easier to revoke. JWTs shine when many services or mobile apps must check identity without a shared session store.

Watch the lesson

JSON Web Tokens (JWT) · 1/7

JSON Web Tokens

A JWT is a signed token that carries facts about the user. Let us open one up.

Prefer a video by a teacher? Find free videos on “jwt authentication explained access token refresh token” on YouTube ↗

In real life: A food delivery app and its API

When you log in on a food delivery app, the backend returns a short-lived access token (a JWT with sub, exp and your role) and a refresh token. Each API call sends the JWT in the Authorization: Bearer header. The order service and the payment service both verify the signature with the public key, without calling the login service. Every 15 minutes the app quietly uses the refresh token to get a new JWT.

Practice (0/2 done)

Task 1 · Code · Javascript

Write decodePayload(token) that returns the payload object of a JWT: take the middle part, turn base64url into base64 (- becomes +, _ becomes /), decode it with atob, and JSON.parse it. Also write isExpired(payload, nowSeconds) that returns true when the payload has no numeric exp, or when nowSeconds >= exp.

Task 2 · Code · Javascript

Write async signHS256(payload, secret) and async verifyHS256(token, secret). Sign: header = base64url of JSON.stringify({ alg: "HS256", typ: "JWT" }), body = base64url of JSON.stringify(payload), signature = HMAC-SHA256 of "header.body" with the secret (crypto.subtle.importKey("raw", ..., { name: "HMAC", hash: "SHA-256" }, false, ["sign", "verify"]) and crypto.subtle.sign). Return "header.body.signature". Verify: return the payload object if the signature is right (use crypto.subtle.verify), otherwise null. The base64url helpers are given.

Quick quiz

Question 1

1.What are the three parts of a JWT?

Question 2

2.Can anyone read the payload of a JWT?

Question 3

3.What does the exp claim mean?

Question 4

4.Why do RS256 tokens suit many separate services?

Question 5

5.A user logs out, but their JWT has 10 minutes left. What is true?

Read more (free)

Pass the quiz (60% or more) or mark this topic as done when you are ready.

Your progress is saved on this device only.

← Previous: Sessions and cookies