🔐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