# JSON Web Tokens (JWT) Complete Guide: Authentication Explained

# The Complete Guide to JSON Web Tokens (JWT)

## What is JWT?

JSON Web Token (JWT) is an open standard (RFC 7519) that defines a compact and self-contained way for securely transmitting information between parties as a JSON object. This information can be verified and trusted because it is digitally signed using a secret (with HMAC algorithm) or a public/private key pair (using RSA or ECDSA).

JWTs are primarily used for authentication and information exchange in modern web applications. Unlike traditional session-based authentication where the server stores session data, JWTs are stateless—all necessary information is contained within the token itself.

## JWT Structure

A JWT consists of three parts separated by dots (.):

**header.payload.signature**

### 1. Header
The header typically consists of two parts: the token type (JWT) and the signing algorithm (HMAC, RSA, or ECDSA).

```json
{
  "alg": "HS256",
  "typ": "JWT"
}
```

### 2. Payload
The payload contains the claims—statements about an entity (typically the user) and additional data. There are three types of claims:

- **Registered claims**: Predefined claims like `iss` (issuer), `exp` (expiration), `sub` (subject), `aud` (audience)
- **Public claims**: Custom claims defined by those using JWTs
- **Private claims**: Custom claims for sharing information between parties

```json
{
  "sub": "1234567890",
  "name": "John Doe",
  "admin": true,
  "iat": 1516239022,
  "exp": 1516242622
}
```

### 3. Signature
The signature is created by taking the encoded header, encoded payload, a secret, and signing them using the algorithm specified in the header.

```
HMACSHA256(
  base64UrlEncode(header) + "." + base64UrlEncode(payload),
  secret
)
```

## How JWT Works

1. **User Login**: User submits credentials to the server
2. **Token Generation**: Server validates credentials and generates a JWT
3. **Token Storage**: Client stores the JWT (typically in localStorage or httpOnly cookies)
4. **Authenticated Requests**: Client includes JWT in the Authorization header
5. **Token Verification**: Server verifies the token signature and extracts user information
6. **Access Granted/Denied**: Server processes the request based on token validity

## Implementation Examples

### Node.js Implementation

```javascript
const jwt = require('jsonwebtoken');
const express = require('express');
const app = express();

const SECRET_KEY = 'your-secret-key-keep-it-safe';

// Generate JWT
app.post('/login', (req, res) => {
  const user = { id: 123, username: 'john_doe', role: 'admin' };
  
  const token = jwt.sign(
    { userId: user.id, username: user.username, role: user.role },
    SECRET_KEY,
    { expiresIn: '1h' }
  );
  
  res.json({ token });
});

// Verify JWT Middleware
const authenticateToken = (req, res, next) => {
  const authHeader = req.headers['authorization'];
  const token = authHeader && authHeader.split(' ')[1];
  
  if (!token) return res.sendStatus(401);
  
  jwt.verify(token, SECRET_KEY, (err, user) => {
    if (err) return res.sendStatus(403);
    req.user = user;
    next();
  });
};

// Protected Route
app.get('/protected', authenticateToken, (req, res) => {
  res.json({ message: 'Access granted', user: req.user });
});
```

### Python Implementation

```python
import jwt
from datetime import datetime, timedelta
from flask import Flask, request, jsonify

app = Flask(__name__)
SECRET_KEY = 'your-secret-key-keep-it-safe'

# Generate JWT
@app.route('/login', methods=['POST'])
def login():
    user = {'id': 123, 'username': 'john_doe', 'role': 'admin'}
    
    payload = {
        'user_id': user['id'],
        'username': user['username'],
        'role': user['role'],
        'exp': datetime.utcnow() + timedelta(hours=1),
        'iat': datetime.utcnow()
    }
    
    token = jwt.encode(payload, SECRET_KEY, algorithm='HS256')
    return jsonify({'token': token})

# Verify JWT
def verify_token(token):
    try:
        payload = jwt.decode(token, SECRET_KEY, algorithms=['HS256'])
        return payload
    except jwt.ExpiredSignatureError:
        return None
    except jwt.InvalidTokenError:
        return None

# Protected Route
@app.route('/protected')
def protected():
    auth_header = request.headers.get('Authorization')
    if not auth_header:
        return jsonify({'error': 'No token provided'}), 401
    
    token = auth_header.split(' ')[1]
    payload = verify_token(token)
    
    if not payload:
        return jsonify({'error': 'Invalid token'}), 403
    
    return jsonify({'message': 'Access granted', 'user': payload})
```

## Refresh Tokens

Refresh tokens solve the problem of short-lived access tokens. The pattern works as follows:

1. Issue a short-lived access token (15 minutes) and a long-lived refresh token (7 days)
2. Store refresh tokens securely in the database
3. When access token expires, use refresh token to obtain a new access token
4. Implement refresh token rotation for enhanced security

```javascript
// Refresh token endpoint
app.post('/refresh', (req, res) => {
  const { refreshToken } = req.body;
  
  // Verify refresh token from database
  if (!isValidRefreshToken(refreshToken)) {
    return res.sendStatus(403);
  }
  
  const newAccessToken = jwt.sign(
    { userId: user.id },
    SECRET_KEY,
    { expiresIn: '15m' }
  );
  
  res.json({ accessToken: newAccessToken });
});
```

## Security Best Practices

1. **Use Strong Secrets**: Generate cryptographically secure random strings
2. **Set Expiration Times**: Always include `exp` claim to limit token lifetime
3. **Use HTTPS**: Never transmit JWTs over unencrypted connections
4. **Store Securely**: Use httpOnly cookies or secure storage mechanisms
5. **Validate All Claims**: Check `exp`, `iss`, `aud` claims on every request
6. **Use Appropriate Algorithms**: Prefer RS256 over HS256 for public applications
7. **Implement Token Blacklisting**: Maintain a blacklist for revoked tokens
8. **Don't Store Sensitive Data**: JWTs are encoded, not encrypted

## Common Vulnerabilities

- **Algorithm Confusion**: Attackers change `alg` to "none" to bypass signature verification
- **Weak Secrets**: Using predictable or short secrets enables brute-force attacks
- **Missing Expiration**: Tokens without expiration remain valid indefinitely
- **XSS Attacks**: Storing tokens in localStorage exposes them to JavaScript
- **Token Leakage**: Logging or exposing tokens in URLs

## JWT vs Sessions

**JWT Advantages:**
- Stateless and scalable
- Works across domains
- Mobile-friendly
- Reduced database queries

**Session Advantages:**
- Immediate revocation
- Smaller payload size
- Server-side control
- Better for sensitive applications

## Real-World Example

A typical authentication flow in a React/Node.js application:

```javascript
// Client-side login
const login = async (credentials) => {
  const response = await fetch('/api/login', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(credentials)
  });
  
  const { token } = await response.json();
  localStorage.setItem('token', token);
};

// Making authenticated requests
const fetchUserData = async () => {
  const token = localStorage.getItem('token');
  const response = await fetch('/api/user', {
    headers: { 'Authorization': `Bearer ${token}` }
  });
  return response.json();
};
```

JWTs provide a powerful, flexible authentication mechanism when implemented correctly with proper security measures.
