🔐Encoding & Escaping
JWT Token Structure
Understand JWT encoding, structure, and validation
Explanation
JWT (JSON Web Token) consists of three Base64-encoded parts: header, payload, and signature, separated by dots.
Examples
JWT structure
Input
header.payload.signature
Output
eyJ...}.eyJ...}.SflK...
Decoded header
Input
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
Output
{"alg":"HS256","typ":"JWT"}Code Examples
JavaScript
// JWT structure: header.payload.signature
// Each part is Base64URL encoded
// Decode JWT (without verification)
function decodeJwt(token) {
const parts = token.split('.');
if (parts.length !== 3) {
throw new Error('Invalid JWT format');
}
const [headerB64, payloadB64, signature] = parts;
// Base64URL decode
const base64UrlDecode = (str) => {
// Convert Base64URL to Base64
str = str.replace(/-/g, '+').replace(/_/g, '/');
// Pad with =
while (str.length % 4) {
str += '=';
}
return atob(str);
};
return {
header: JSON.parse(base64UrlDecode(headerB64)),
payload: JSON.parse(base64UrlDecode(payloadB64)),
signature
};
}
// Usage
const token = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c';
const decoded = decodeJwt(token);
console.log(decoded);
// {
// header: { alg: 'HS256', typ: 'JWT' },
// payload: { sub: '1234567890', name: 'John Doe', iat: 1516239022 },
// signature: '...'
// }
// Create JWT (use library in production!)
// npm install jsonwebtoken
const jwt = require('jsonwebtoken');
const payload = {
sub: '1234567890',
name: 'John Doe',
iat: Math.floor(Date.now() / 1000)
};
const secret = 'your-256-bit-secret';
// Sign token
const token = jwt.sign(payload, secret, {
algorithm: 'HS256',
expiresIn: '1h'
});
// Verify and decode token
try {
const decoded = jwt.verify(token, secret);
console.log(decoded);
} catch (error) {
console.error('Invalid token:', error.message);
}
// Check expiration
function isTokenExpired(token) {
const decoded = decodeJwt(token);
const exp = decoded.payload.exp;
if (!exp) return false;
return Date.now() >= exp * 1000;
}
// Refresh token pattern
async function refreshAccessToken(refreshToken) {
try {
const decoded = jwt.verify(refreshToken, REFRESH_SECRET);
// Generate new access token
const newToken = jwt.sign(
{ sub: decoded.sub },
ACCESS_SECRET,
{ expiresIn: '15m' }
);
return newToken;
} catch (error) {
throw new Error('Invalid refresh token');
}
} Python
import jwt
import json
import base64
from datetime import datetime, timedelta
# Decode JWT (without verification)
def decode_jwt_unsafe(token):
parts = token.split('.')
if len(parts) != 3:
raise ValueError('Invalid JWT format')
header_b64, payload_b64, signature = parts
# Base64URL decode
def base64_url_decode(s):
# Convert Base64URL to Base64
s = s.replace('-', '+').replace('_', '/')
# Add padding
return base64.b64decode(s + '=' * (4 - len(s) % 4))
header = json.loads(base64_url_decode(header_b64))
payload = json.loads(base64_url_decode(payload_b64))
return {
'header': header,
'payload': payload,
'signature': signature
}
# Create JWT (use PyJWT library)
# pip install PyJWT
payload = {
'sub': '1234567890',
'name': 'John Doe',
'iat': datetime.utcnow(),
'exp': datetime.utcnow() + timedelta(hours=1)
}
secret = 'your-256-bit-secret'
# Encode token
token = jwt.encode(payload, secret, algorithm='HS256')
# Decode and verify token
try:
decoded = jwt.decode(token, secret, algorithms=['HS256'])
print(decoded)
except jwt.ExpiredSignatureError:
print('Token expired')
except jwt.InvalidTokenError:
print('Invalid token')
# Decode without verification (for inspection only)
decoded_unverified = jwt.decode(token, options={"verify_signature": False})
# Check if token is expired
def is_token_expired(token):
try:
jwt.decode(token, secret, algorithms=['HS256'])
return False
except jwt.ExpiredSignatureError:
return True
except jwt.InvalidTokenError:
return None # Invalid for other reasons💡 Tips
- JWT is Base64URL encoded (not Base64)
- Never store sensitive data in JWT (it's not encrypted)
- Always verify signature before trusting payload
- Use short expiration times for access tokens
- Store refresh tokens securely (httpOnly cookie)
- Include iat (issued at) and exp (expiration) claims
- Use strong secrets (at least 256 bits)
- Consider using asymmetric algorithms (RS256) for microservices
⚠️ Common Pitfalls
- JWT payload is not encrypted (anyone can decode)
- Not verifying signature = security vulnerability
- Using weak secrets
- Storing JWT in localStorage (XSS risk)
- No token revocation without additional infrastructure
- Including sensitive data in payload
- Not checking expiration
- Using symmetric keys in distributed systems