Back

JWT Authentication: Complete Guide to JSON Web Tokens

JWT Authentication: Complete Guide to JSON Web Tokens

JSON Web Tokens (JWT) have become the de facto standard for modern web authentication. Whether you're building a single-page application, mobile app, or microservices architecture, understanding JWT is essential for secure user authentication and authorization.

What is JWT Authentication?

JWT authentication is a stateless authentication method where the server issues a signed token containing user information. Unlike traditional session-based authentication, JWT tokens are self-contained and don't require server-side storage.

How JWT Authentication Works

The JWT authentication flow consists of these steps:

  1. User Login: User submits credentials (username/password) to the authentication server
  2. Token Generation: Server validates credentials and creates a signed JWT
  3. Token Delivery: Server sends the JWT to the client
  4. Token Storage: Client stores the token (localStorage, sessionStorage, or cookie)
  5. Authenticated Requests: Client includes JWT in the Authorization header
  6. Token Verification: Server verifies the signature and processes the request

JWT Structure Explained

A JWT consists of three Base64Url-encoded parts separated by dots:

header.payload.signature

Header

The header typically contains two fields:

{
  "alg": "HS256",
  "typ": "JWT"
}
  • alg: The signing algorithm (HS256, RS256, ES256, etc.)
  • typ: Token type, always "JWT"

Payload

The payload contains claims - statements about the entity and additional data:

{
  "sub": "1234567890",
  "name": "John Doe",
  "email": "john@example.com",
  "role": "admin",
  "iat": 1516239022,
  "exp": 1516242622
}

Registered Claims:

  • iss (Issuer): Token issuer
  • sub (Subject): User identifier
  • aud (Audience): Intended recipients
  • exp (Expiration): Expiration timestamp
  • nbf (Not Before): Valid from timestamp
  • iat (Issued At): Token creation time
  • jti (JWT ID): Unique identifier

Signature

The signature ensures the token hasn't been tampered with:

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

When to Use JWT Authentication

Ideal Use Cases

Scenario Why JWT Works
Microservices Stateless verification across services
Mobile Apps No cookie dependency, easy storage
Single-Page Apps Clean separation of frontend/backend
Third-Party APIs Standard format, widely supported
SSO Systems Share authentication across domains

When to Avoid JWT

Scenario Better Alternative
Simple Web Apps Session-based auth
Immediate Revocation Needed Session with database
Sensitive Data Storage Server-side sessions
Small Scale Applications Session cookies

JWT Implementation Best Practices

1. Use Strong Secrets

// ❌ Bad: Weak secret
const secret = 'password123';

// ✅ Good: Strong random secret
const secret = crypto.randomBytes(64).toString('hex');

2. Set Appropriate Expiration

// ✅ Access token: 15-60 minutes
const accessToken = jwt.sign(payload, secret, { 
  expiresIn: '15m' 
});

// ✅ Refresh token: 7-30 days
const refreshToken = jwt.sign(payload, secret, { 
  expiresIn: '7d' 
});

3. Use HTTPS Always

JWT tokens are visible to anyone who intercepts them. Always transmit over HTTPS to prevent token theft.

4. Implement Refresh Tokens

// Token refresh endpoint
app.post('/refresh', (req, res) => {
  const refreshToken = req.body.refreshToken;
  
  if (isValidRefreshToken(refreshToken)) {
    const newAccessToken = generateAccessToken(userId);
    res.json({ accessToken: newAccessToken });
  } else {
    res.status(401).json({ error: 'Invalid refresh token' });
  }
});

5. Store Tokens Securely

Storage Method Security Recommendation
localStorage Low XSS vulnerable, avoid
sessionStorage Low XSS vulnerable, avoid
HttpOnly Cookie High CSRF protection needed
Memory Highest Lost on page refresh

Best Practice:

  • For web apps: Use HttpOnly cookies with SameSite=Strict for access tokens (prevents XSS access to token)
  • For SPAs: Consider memory storage with refresh token rotation (most secure against XSS)
  • Never use localStorage/sessionStorage for sensitive tokens (vulnerable to XSS attacks)

Common JWT Security Pitfalls

1. Algorithm Confusion Attack

Problem: Accepting alg: "none" or changing algorithms.

Solution: Always verify the algorithm:

const decoded = jwt.verify(token, secret, { 
  algorithms: ['HS256', 'RS256'] 
});

2. Weak Secret Keys

Problem: Using predictable or short secrets.

Solution: Use cryptographically strong secrets (256+ bits).

3. Not Validating Claims

Problem: Accepting tokens without checking exp, iss, aud.

Solution: Validate all claims:

const decoded = jwt.verify(token, secret, {
  issuer: 'your-app.com',
  audience: 'your-app.com',
  clockTimestamp: Date.now() / 1000
});

4. Storing Sensitive Data

Problem: JWT payload is not encrypted.

Solution: Never store passwords, SSN, or PII in JWT. Use JWE for encrypted tokens.

JWT vs Session Authentication

Aspect JWT Session
State Stateless Stateful
Storage Client-side Server-side
Scalability Excellent Requires session store
Revocation Difficult Easy
Token Size Large (1KB+) Small (~50 bytes)
Mobile Support Excellent Limited

JWT Signing Algorithms Comparison

Algorithm Type Key Size Use Case
HS256 HMAC SHA-256 256+ bits Internal services, microservices
RS256 RSA SHA-256 2048+ bits Public APIs, third-party access
ES256 ECDSA P-256 256 bits Modern apps, mobile, IoT

Recommendation:

  • Use RS256 for public APIs (asymmetric - allows token verification without sharing private key)
  • Use HS256 for internal services (symmetric - faster, simpler key management)
  • Use ES256 for performance-critical applications (smaller signature size than RSA)

Testing Your JWT Implementation

Use our free JWT Decoder to:

  1. Verify token structure
  2. Check expiration times
  3. Inspect claims
  4. Debug authentication issues

Conclusion

JWT authentication provides a scalable, stateless solution for modern applications. By following best practices—using strong secrets, implementing refresh tokens, and validating claims—you can build secure authentication systems that scale across microservices, mobile apps, and SPAs.

Key Takeaways:

  • JWT is ideal for stateless, distributed systems
  • Always use HTTPS and strong secrets
  • Implement refresh tokens for better security
  • Never store sensitive data in JWT payload
  • Validate all claims on the server side

For quick JWT debugging, try our JWT Decoder tool.