JSON Web Tokens (JWT)
A JSON Web Token (JWT) is a compact, self-contained way to securely transmit information between two parties — such as a client and a server — as a JSON object. The information inside the token can be verified and trusted because it is digitally signed.
Think of a JWT like an identity badge at a conference. Once issued at the entrance (login), the badge proves who the person is and what areas they are allowed to access — without them having to show their passport every time they move between rooms. The server gives a token after login, and the client presents that token with every subsequent request.
Why JWT?
Traditional web applications use sessions stored on the server. As applications scaled to millions of users, storing session data on the server became a problem. JWT solves this with a stateless approach — all user information is inside the token itself. The server does not need to store anything. It simply verifies the token's signature when the client sends it.
Structure of a JWT
A JWT consists of three parts separated by dots (.):
xxxxx.yyyyy.zzzzzThese three parts are:
- Header — specifies the token type and the algorithm used for signing
- Payload — contains the actual data (claims) — who the user is, their role, when the token expires
- Signature — verifies that the token has not been tampered with
A Real JWT Example
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOjQyLCJuYW1lIjoiUmFqYW4gU2hhcm1hIiwicm9sZSI6InN0dWRlbnQiLCJpYXQiOjE3MDAwMDAwMDAsImV4cCI6MTcwMDAwMzYwMH0.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5cThis looks like random characters, but it is simply Base64-encoded JSON. It can be decoded by anyone — but not modified without invalidating the signature.
Decoding the Three Parts
Part 1 — Header (decoded)
{
"alg": "HS256",
"typ": "JWT"
}"alg" is the signing algorithm (HS256 = HMAC with SHA-256). "typ" confirms this is a JWT.
Part 2 — Payload (decoded)
{
"userId": 42,
"name": "Rajan Sharma",
"role": "student",
"iat": 1700000000,
"exp": 1700003600
}The payload contains the meaningful data called claims:
userIdandname— custom claims about the userrole— what the user is allowed to doiat— Issued At (when the token was created, as a Unix timestamp)exp— Expiry time (when the token becomes invalid)
Part 3 — Signature
The signature is created by the server using the encoded header, encoded payload, and a secret key. The formula is:
HMACSHA256(
base64UrlEncode(header) + "." + base64UrlEncode(payload),
secretKey
)If anyone modifies even a single character in the token, the signature will no longer match — and the server will reject the token.
How JWT Works in a Login Flow
Step 1: User logs in
Client → POST /login { "email": "rajan@example.com", "password": "pass123" }
Step 2: Server verifies credentials and creates a JWT
Server → Response: { "token": "eyJhbGci...SflKxw" }
Step 3: Client stores the token (in localStorage or memory)
Step 4: Client sends the token with every protected request
Client → GET /dashboard
Header: Authorization: Bearer eyJhbGci...SflKxw
Step 5: Server verifies the token signature
If valid → process the request
If expired or tampered → return 401 UnauthorizedStandard JWT Payload Claims
| Claim | Full Name | Meaning |
|---|---|---|
iss | Issuer | Who issued the token (e.g., the website domain) |
sub | Subject | Who the token is about (usually user ID) |
aud | Audience | Who should accept this token |
exp | Expiration | Unix timestamp when the token expires |
iat | Issued At | Unix timestamp when the token was created |
nbf | Not Before | Token is not valid before this timestamp |
jti | JWT ID | A unique identifier for this specific token |
Working with JWT in JavaScript (Client Side)
After receiving a token from the server, it can be stored and included in API requests:
// Step 1: Store the token after login
const token = "eyJhbGci...SflKxw"; // received from server
localStorage.setItem("authToken", token);
// Step 2: Use the token in subsequent API requests
const savedToken = localStorage.getItem("authToken");
fetch("https://api.example.com/profile", {
method: "GET",
headers: {
"Authorization": "Bearer " + savedToken
}
})
.then(function(response) {
return response.json();
})
.then(function(profile) {
console.log("Welcome, " + profile.name);
});Decoding a JWT Without Verification (Inspect Payload)
The payload of a JWT can be decoded in JavaScript without any library — simply by splitting the token and decoding the Base64 part:
function decodeJWT(token) {
const payload = token.split(".")[1];
const decoded = atob(payload);
return JSON.parse(decoded);
}
const token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOjQyLCJuYW1lIjoiUmFqYW4iLCJyb2xlIjoic3R1ZGVudCJ9.signature";
const data = decodeJWT(token);
console.log(data.name); // Output: Rajan
console.log(data.role); // Output: studentImportant: This decodes the payload but does not verify the signature. Signature verification must only happen on the server using the secret key. Never trust decoded JWT data from the client alone without server-side verification.
Security Best Practices for JWT
- Always set an expiry time (
exp) on tokens — avoid tokens that never expire - Keep the secret key on the server only — never expose it in client-side code
- Do not store sensitive information like passwords or bank details in the JWT payload — it is encoded, not encrypted
- Use HTTPS always — JWT tokens sent over plain HTTP can be intercepted
- Prefer storing tokens in memory or httpOnly cookies over localStorage for better security against XSS attacks
- Implement token refresh flows for long-lived sessions instead of long expiry times
JWT vs Traditional Sessions
| Feature | JWT (Stateless) | Server Sessions (Stateful) |
|---|---|---|
| Server Storage | Not required — token is self-contained | Required — session stored in server memory or DB |
| Scalability | Highly scalable — works across multiple servers | Harder to scale — sessions tied to one server |
| Token Revocation | Difficult — token is valid until expiry | Easy — delete the session from server |
| Mobile App Support | Excellent — stateless works well for apps | Requires cookies, less mobile-friendly |
| Payload Visibility | Payload is readable (Base64 encoded) | Session data stays private on server |
Online JWT Tool
The official JWT debugger at jwt.io allows pasting any JWT token and instantly seeing the decoded header, payload, and whether the signature is valid. It is extremely useful for learning, testing, and debugging JWT-based authentication.
Key Points to Remember
- JWT is a compact token format used for authentication and information exchange
- It has three parts: Header, Payload, and Signature — separated by dots
- The payload contains JSON claims — user identity, role, and expiry time
- JWT is stateless — the server does not need to store session data
- The payload is encoded (readable), not encrypted — never store sensitive data in it
- Always verify JWT on the server using the secret key before trusting its data
- Use
jwt.ioto inspect and debug JWT tokens
Summary
JSON Web Tokens are the backbone of modern authentication in web and mobile applications. Built entirely on JSON, they provide a secure, scalable, and stateless method for verifying user identity across API requests. Understanding how JWT is structured and how it flows between client and server gives a strong foundation for building secure, real-world applications.
