JWT Guide: Understanding JSON Web Tokens & Authentication
Master JSON Web Tokens (JWT) with this comprehensive guide. Learn how JWTs work, how to decode them, best practices for security, and when to use them in your applications.
What is JWT?
JWT (JSON Web Token) is a compact, URL-safe way to securely transmit information between parties. It's a token that contains encoded claims (statements about an entity and additional metadata).
Think of it like a digital ID card:
- Self-contained: All user info is inside the token
- Digitally signed: Can't be forged or modified
- Stateless: No need to query a database each time
- Transferable: Can be sent via HTTP headers or cookies
JWTs are commonly used for authentication, authorization, and secure information exchange in APIs.
JWT Structure & Format
A JWT consists of three parts separated by dots (.). Here's a real example:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5cPart 1: Header
Base64-encoded JSON describing the token type and hashing algorithm:
{
"alg": "HS256", // Algorithm (HMAC SHA-256)
"typ": "JWT" // Token type
}Part 2: Payload (Claims)
Base64-encoded JSON containing the actual data:
{
"sub": "1234567890", // Subject (user ID)
"name": "John Doe", // User name
"email": "[email protected]",
"iat": 1516239022, // Issued at (timestamp)
"exp": 1516242622, // Expiration time
"admin": true // Custom claims
}Standard claims include: iss (issuer), sub (subject), aud (audience), iat (issued at), exp (expiration).
Part 3: Signature
Cryptographic signature ensuring the token hasn't been tampered with:
HMACSHA256(
base64UrlEncode(header) + "." + base64UrlEncode(payload),
secret_key
)Only the server with the secret key can create or verify the signature.
How JWT Authentication Works
Here's the typical JWT authentication flow:
- User logs in with username & password
- Server validates credentials against database
- Server creates JWT with user data and signs it
- Token sent to client (usually in response body)
- Client stores token (usually in localStorage or sessionStorage)
- Client sends token with each request in Authorization header:
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...- Server verifies token on each protected endpoint
- Server grants access if signature is valid and not expired
Key advantage: No need to query the database for every request. The token itself contains all necessary user information.
Decoding JWT Tokens
Decoding is simple: split by "." and base64-decode each part:
JavaScript Example:
function decodeJWT(token) {
const parts = token.split('.');
const header = JSON.parse(atob(parts[0]));
const payload = JSON.parse(atob(parts[1]));
return {
header,
payload,
signature: parts[2]
};
}
const jwt = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...';
const decoded = decodeJWT(jwt);
console.log(decoded.payload); // { sub: '123', name: 'John', ... }Python Example:
import jwt
import json
import base64
token = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...'
# Method 1: Using jwt library (simpler)
decoded = jwt.decode(token, options={"verify_signature": False})
print(decoded)
# Method 2: Manual decoding
parts = token.split('.')
header = json.loads(base64.urlsafe_b64decode(parts[0] + '=='))
payload = json.loads(base64.urlsafe_b64decode(parts[1] + '=='))
print(payload)⚠️ Important: Base64 is NOT encryption. Decoding doesn't require the secret key. Never put sensitive passwords or credit card info in JWT claims!
Verifying JWT Signatures
Decoding and verifying are different. To verify that a JWT is legitimate, you must check the signature:
JavaScript Example:
// Install: npm install jsonwebtoken
const jwt = require('jsonwebtoken');
const token = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...';
const secret = 'your-secret-key';
try {
const decoded = jwt.verify(token, secret);
console.log('Token is valid:', decoded);
} catch (error) {
console.error('Token is invalid:', error.message);
// Possible errors: TokenExpiredError, JsonWebTokenError
}Python Example:
import jwt
token = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...'
secret = 'your-secret-key'
try:
decoded = jwt.decode(token, secret, algorithms=['HS256'])
print('Token is valid:', decoded)
except jwt.ExpiredSignatureError:
print('Token has expired')
except jwt.InvalidTokenError:
print('Token is invalid')The verification process recalculates the signature using the secret key and compares it with the signature in the token. If they match, the token is valid and hasn't been tampered with.
Security Best Practices
1. Use HTTPS Always
Always transmit JWTs over HTTPS, never HTTP. JWTs are signed but not encrypted, so they can be read if transmitted insecurely.
2. Set Expiration Times
Always include an exp claim and refresh tokens regularly:
const payload = {
sub: user.id,
name: user.name,
iat: Math.floor(Date.now() / 1000),
exp: Math.floor(Date.now() / 1000) + (15 * 60) // 15 minutes
};3. Use Strong Secret Keys
- Use at least 256-bit keys (32 bytes)
- Rotate keys periodically
- Never commit secrets to version control
- Store in environment variables or secret managers
4. Implement Refresh Tokens
Use short-lived access tokens (15 min) with longer-lived refresh tokens (7 days):
// Access token: 15 minutes
const accessToken = jwt.sign(
{ sub: user.id },
secret,
{ expiresIn: '15m' }
);
// Refresh token: 7 days
const refreshToken = jwt.sign(
{ sub: user.id, type: 'refresh' },
refreshSecret,
{ expiresIn: '7d' }
);5. Avoid Sensitive Data
Don't include passwords, credit cards, or PII in JWT claims. Only include data you don't mind a user seeing (it's just base64 encoded, not encrypted).
6. Validate Claims
Always validate all claims on the server:
const decoded = jwt.verify(token, secret);
// Validate claims
if (decoded.exp < Math.floor(Date.now() / 1000)) {
throw new Error('Token expired');
}
if (!decoded.sub) {
throw new Error('Invalid token: missing subject');
}
if (decoded.aud !== expectedAudience) {
throw new Error('Invalid audience');
}When to Use JWT
✅ Good Use Cases
- REST APIs: Stateless authentication between client and server
- Microservices: Pass authentication context between services
- Single Page Apps (SPAs): Browser-based authentication
- Mobile Apps: Lightweight, efficient authentication
- Cross-Domain: CORS-friendly authentication
- Third-party integrations: OAuth authorization flows
❌ Avoid JWT For
- Traditional server-side sessions: Use cookies instead
- Sensitive operations: Combine with other verification methods
- Data that changes frequently: Session claims might become stale
- Immediate revocation: JWTs can't be revoked until expiration (use blacklist if needed)
Standard JWT Claims Reference
| Claim | Description |
|---|---|
iss | Issuer (who created the token) |
sub | Subject (user ID) |
aud | Audience (who should receive this token) |
exp | Expiration time (Unix timestamp) |
iat | Issued at (Unix timestamp) |
nbf | Not before (token valid from this time) |
Related Tools
Try Our JWT Decoder
Instantly decode and verify JWT tokens with our free JWT Decoder tool.
Open JWT Decoder →