What is a JWT — Simple Explanation with Examples
A JWT (JSON Web Token, pronounced “jot”) is a compact, URL-safe token format that encodes claims (statements) about a user or entity as a JSON object. JWTs are digitally signed, so the receiver can verify they were issued by a trusted source and have not been tampered with.
What You’ll Learn
This article explains the JWT structure, how it differs from encryption, how to decode and verify tokens, and how they are used for authentication and information exchange. JWTs are the standard token format in modern APIs, OAuth 2.0, and OpenID Connect.
The Problem JWTs Solve
In a traditional web app with server-side sessions:
- The server creates a session and stores it in a database or in-memory store.
- The server sends a session cookie to the client.
- On every request, the client sends the cookie, and the server looks up the session in its store.
This works but has drawbacks:
- Server memory — Session storage consumes server resources.
- Scaling — Load-balanced servers must share a session store (Redis, database), adding complexity.
- Coupling — The session data lives on the server; the client cannot read it.
JWTs solve this by being self-contained. All the information is inside the token. The server validates the signature — if valid, the token is trusted. No database lookup required. This makes JWTs stateless and horizontally scalable.
The Digital Passport Analogy
A JWT is like a passport:
- It contains claims about the bearer: name, nationality, expiration date (header + payload).
- It has a stamp and hologram (signature) that proves it was issued by a legitimate authority (issuer).
- Any border control agent (API server) can verify the passport without calling the issuing country’s database, because the security features are self-contained.
- The passport expires, so it must be renewed periodically.
- The bearer cannot modify their passport — tampering breaks the hologram (signature).
Like a passport, a JWT is verifiable without contacting the issuer, but the sensitive claims inside can be read by anyone who has the token.
JWT Structure
A JWT consists of three parts separated by dots:
header.payload.signatureeyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.
eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkFsaWNlIiwiaWF0IjoxNTE2MjM5MDIyfQ.
SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5cLet’s decode each part.
Header
{
"alg": "HS256",
"typ": "JWT"
}The header specifies the signing algorithm (HS256, RS256, etc.) and the token type.
Payload (Claims)
{
"sub": "1234567890",
"name": "Alice",
"iat": 1516239022
}The payload contains claims — statements about the entity (user) and additional metadata. Common registered claims:
| Claim | Full Name | Purpose |
|---|---|---|
sub | Subject | Identifier for the user (usually user ID) |
iss | Issuer | Who created and signed the token |
aud | Audience | Who the token is intended for |
exp | Expiration | Unix timestamp when token expires |
iat | Issued At | Unix timestamp when token was issued |
nbf | Not Before | Token is not valid before this time |
Signature
The signature is created by taking the encoded header and payload, and signing them with a secret key using the algorithm specified in the header.
HMACSHA256(
base64UrlEncode(header) + "." + base64UrlEncode(payload),
secret
)The receiver recomputes the signature using the same key. If it matches, the token is authentic.
Encoding vs Encryption
A common misconception: JWTs are not encrypted by default. They are encoded (base64url) and signed. Anyone with the token can decode it and read the claims:
# Decode a JWT payload on the command line
echo "eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkFsaWNlIiwiaWF0IjoxNTE2MjM5MDIyfQ" | base64 -d
# Output:
# {"sub":"1234567890","name":"Alice","iat":1516239022}Do not store sensitive data (passwords, credit card numbers) in a JWT payload. If you need confidentiality, use JWE (JSON Web Encryption) or pass the token over HTTPS (which you should always do anyway).
Example: Parsing and Verifying a JWT
Node.js (jsonwebtoken library)
import jwt from 'jsonwebtoken';
const SECRET = 'your-256-bit-secret';
// Create (sign) a JWT
const token = jwt.sign(
{ userId: 42, role: 'admin' },
SECRET,
{ expiresIn: '1h' }
);
console.log('Token:', token);
// Token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOjQyLCJyb2xlIjoiYWRtaW4iLCJpYXQiOjE3MTg4OTEyMzQsImV4cCI6MTcxODg5NDgzNH0.abc123...
// Verify and decode
try {
const decoded = jwt.verify(token, SECRET);
console.log('Decoded:', decoded);
// { userId: 42, role: 'admin', iat: 1718891234, exp: 1718894834 }
} catch (err) {
console.error('Invalid token:', err.message);
}
// Token expiration check is automatic — jwt.verify returns the payload
// or throws if expired
Python (PyJWT library)
import jwt
SECRET = "your-256-bit-secret"
# Create a JWT
payload = {"user_id": 42, "role": "admin"}
token = jwt.encode(payload, SECRET, algorithm="HS256")
print("Token:", token)
# Verify and decode
try:
decoded = jwt.decode(token, SECRET, algorithms=["HS256"])
print("Decoded:", decoded)
# {'user_id': 42, 'role': 'admin', 'iat': 1718891234, 'exp': 1718894834}
except jwt.ExpiredSignatureError:
print("Token expired")
except jwt.InvalidTokenError:
print("Invalid token")How JWT Authentication Works
1. User logs in with credentials (email + password)
2. Server validates credentials
3. Server creates a JWT with user claims (userId, role, etc.) and signs it
4. Server returns the JWT to the client
5. Client stores the JWT (localStorage, sessionStorage, or httpOnly cookie)
6. Client sends the JWT with every API request:
Authorization: Bearer <token>
7. Server verifies the signature on each request (no DB lookup needed)
8. If valid, server trusts the claims and processes the requestSecurity Considerations
- Always use HTTPS — Without TLS, a JWT can be intercepted and replayed.
- Set short expiration — Use
expclaims of 15–60 minutes. Short-lived tokens limit damage from leaks. - Use a strong secret — For HS256, use a cryptographically random string of at least 256 bits.
- Use RS256 in production — RS256 (RSA) uses public/private key pairs. The private key signs, public keys verify. Services can verify without knowing the signing key.
- Validate all claims — Always check
exp,iss,aud, andnbfon every verification. - Never store secrets in JWTs — The payload is readable by anyone. No passwords, no API keys.
Common Use Cases
Authentication — After login, the server returns a JWT. The client includes it in the
Authorizationheader for subsequent API calls. No session storage needed.OAuth 2.0 access tokens — OAuth 2.0 often uses JWTs as access tokens. The resource server decodes the JWT to determine user identity and permissions.
OpenID Connect ID tokens — OpenID Connect uses JWTs as ID tokens to communicate authenticated user identity from the identity provider to the application.
Stateless API authorization — Microservices validate JWTs without sharing a session store. A central auth service issues tokens that any service can verify.
Single Sign-On (SSO) — A user authenticates once with an identity provider, which issues a JWT. Multiple applications accept the same JWT for seamless cross-app authentication.
FAQ
Related Terms
What is OAuth 2.0 — What is an API — What is a REST API — What is a Microservice
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro