JSON Web Tokens (JWTs) are the most common way to handle authentication in modern APIs. This guide explains how they work, how to use them correctly, and what mistakes to avoid.

What is a JWT?

A JWT is a compact, self-contained token that encodes claims (pieces of information) about a user. It has three parts separated by dots:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.
eyJzdWIiOiJ1c3JfMTIzIiwibmFtZSI6IkFsaWNlIiwiaWF0IjoxNzAwMDAwMDAwLCJleHAiOjE3MDAwMDM2MDB9.
SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
  • Header (red) — algorithm and token type
  • Payload (blue) — claims (user data)
  • Signature (green) — cryptographic verification

Decode the header and payload

// Each part is Base64URL encoded
// Header decodes to:
{ "alg": "HS256", "typ": "JWT" }

// Payload decodes to:
{
  "sub": "usr_123",      // subject (user ID)
  "name": "Alice",
  "iat": 1700000000,     // issued at (Unix timestamp)
  "exp": 1700003600      // expires at (1 hour later)
}

Create a JWT in JavaScript (Node.js)

const jwt = require('jsonwebtoken'); // npm install jsonwebtoken

const secret = process.env.JWT_SECRET; // keep this secret!

// Sign a token
const token = jwt.sign(
  { sub: 'usr_123', name: 'Alice', role: 'admin' },
  secret,
  { expiresIn: '1h' }
);

// Verify a token
try {
  const payload = jwt.verify(token, secret);
  console.log(payload.sub); // 'usr_123'
} catch (error) {
  if (error.name === 'TokenExpiredError') console.log('Token expired');
  if (error.name === 'JsonWebTokenError') console.log('Invalid token');
}

Create a JWT in Python

import jwt  # pip install PyJWT
from datetime import datetime, timedelta, timezone

secret = 'your-secret-key'

# Create token
payload = {
    'sub': 'usr_123',
    'name': 'Alice',
    'iat': datetime.now(timezone.utc),
    'exp': datetime.now(timezone.utc) + timedelta(hours=1)
}
token = jwt.encode(payload, secret, algorithm='HS256')

# Decode and verify
try:
    data = jwt.decode(token, secret, algorithms=['HS256'])
    print(data['sub'])  # usr_123
except jwt.ExpiredSignatureError:
    print('Token expired')
except jwt.InvalidTokenError:
    print('Invalid token')

Standard JWT claims

  • sub — Subject (user ID)
  • iss — Issuer (your app name/URL)
  • aud — Audience (intended recipient)
  • exp — Expiration time (Unix timestamp)
  • iat — Issued at time
  • nbf — Not before time
  • jti — JWT ID (unique identifier)

Critical security mistakes

  • Using "none" algorithm — never accept tokens with "alg":"none"
  • Storing in localStorage — vulnerable to XSS. Use httpOnly cookies instead.
  • Putting sensitive data in payload — JWTs are encoded, not encrypted. Anyone can decode them.
  • Not checking expiry — always verify the exp claim
  • Weak secrets — use at least 256 bits of randomness: openssl rand -hex 32

Try it free — JWT Decoder

Decode and inspect any JWT token instantly — see header, payload, and expiry.

Open tool →