Get a Pentest and security assessment of your IT network.

Cyber Security

JWT Session Tokens: Security Best Practices

TL;DR

Bearer JWT session tokens need careful handling to prevent security issues. This guide covers how to store, transmit, and validate them securely.

1. Understanding the Risks

JWT (JSON Web Token) session tokens are commonly used for authentication. However, they can be vulnerable if not managed correctly:

  • Storage: Storing JWTs insecurely (e.g., in local storage without protection) makes them susceptible to XSS attacks.
  • Transmission: Sending JWTs over unencrypted connections (HTTP instead of HTTPS) exposes them to interception.
  • Validation: Incorrect validation can allow attackers to use expired or tampered tokens.

2. Secure Storage

Avoid storing JWTs in local storage whenever possible. Here are better options:

  1. HTTP-only Cookies (Recommended): Use HTTP-only cookies with the Secure and SameSite=Strict attributes. This prevents JavaScript access and mitigates XSS risks.
    • Example (setting a cookie in Python/Flask):
    • from flask import Flask, make_response
      
      app = Flask(__name__)
      
      @app.route('/login')
      def login():
        token = 'your_jwt_token'
        resp = make_response('Login successful!')
        resp.set_cookie('session_token', token, httponly=True, secure=True, samesite='Strict')
        return resp
  2. In-Memory Storage (for Single Page Applications): If using a SPA, store the JWT in memory and retrieve it only when needed.
  3. Web Workers: Store tokens within Web Workers to isolate them from the main thread’s XSS vulnerabilities.

3. Secure Transmission

Always transmit JWTs over HTTPS (TLS/SSL). This encrypts the communication channel, preventing interception.

  • Ensure your website has a valid SSL certificate. Check for the padlock icon in the browser’s address bar.
  • Redirect HTTP traffic to HTTPS: Configure your web server to automatically redirect all HTTP requests to their HTTPS equivalents.

4. Robust Validation

Implement thorough JWT validation on the server-side.

  1. Verify Signature: Always verify the token’s signature using your secret key or public key (depending on the signing algorithm).
    • Example (using a library in Node.js/jsonwebtoken):
    • const jwt = require('jsonwebtoken');
      
      token = 'your_jwt_token'
      
      jwt.verify(token, 'your_secret_key', (err, decoded) => {
        if (err) {
          // Token is invalid
          console.error(err);
          return res.status(401).send('Invalid token');
        } else {
          // Token is valid
          console.log(decoded);
          return res.status(200).send('Token verified successfully');
        }
      });
  2. Check Expiration (exp claim): Ensure the token hasn’t expired.
  3. Validate Issuer (iss claim) and Audience (aud claim): Confirm that the token was issued for your application.
  4. Consider Refresh Tokens: Use short-lived access tokens combined with long-lived refresh tokens to minimize the impact of compromised tokens.

5. Additional Security Measures

  • Token Revocation: Implement a mechanism to revoke tokens (e.g., by storing revoked token IDs in a database).
  • Rate Limiting: Limit the number of login attempts and token refresh requests to prevent brute-force attacks.
  • Content Security Policy (CSP): Use CSP headers to mitigate XSS vulnerabilities.
Related posts
Cyber Security

Zip Codes & PII: Are They Personal Data?

Cyber Security

Zero-Day Vulnerabilities: User Defence Guide

Cyber Security

Zero Knowledge Voting with Trusted Server

Cyber Security

ZeroNet: 51% Attack Risks & Mitigation