Understanding JWT: Pros, Cons, and Best Security Practices

Prashant BalePrashant Bale
6 min read

What is JWT (JSON Web Token)?

Imagine you're handing a VIP pass to someone for a concert. This pass grants them access to specific areas and activities. In the digital world, JSON Web Token (JWT) works similarly. It's an open standard (RFC 7519) that securely transmits information between parties as a JSON object. This information can be verified and trusted because it is digitally signed using a secret (HMAC) or a public/private key pair (RSA/ECDSA).

JWTs are commonly used in authentication and authorization mechanisms, allowing users to authenticate once and receive a token that grants access to protected resources.


Structure of a JWT

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

<header>.<payload>.<signature>

1. Header

Contains metadata about the token, including the type of token (JWT) and the signing algorithm (HS256, RS256, etc.).

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

2. Payload

Contains claims (data) about the user, such as their user ID, role, and expiration time.

{
  "sub": "1234567890",
  "name": "John Doe",
  "role": "admin",
  "iat": 1708275200,   // Issued At
  "exp": 1708361600    // Expiration time
}

3. Signature

The signature is created by signing the encoded header and encoded payload using a secret key or a private key.

For HMAC (HS256) algorithm:

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

When a client sends a JWT to a server, the server verifies the signature before processing the request.

🔐 Complete JWT Token

Combining all three parts (header.payload.signature):

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.
eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwicm9sZSI6ImFkbWluIiwiaWF0IjoxNzA4Mjc1MjAwLCJleHAiOjE3MDgzNjE2MDB9.
uPMQ1yRyUzv1UKX2RfBdOwzMg2FajRMiWBJDtx7x3kM


⚙️ Step-by-Step JWT Authentication Flow

🧾 Example: User Login Process

Scenario: A user logs into a web application.

Step 1: User Logs In

The user provides valid credentials (username & password).

Request:

httpCopyEditPOST /api/login
Content-Type: application/json

{
  "username": "john.doe",
  "password": "mypassword123"
}

Step 2: Server Validates Credentials

The server checks the username and password against its database.

If valid, the server generates a JWT like this:

JWT Payload:

jsonCopyEdit{
  "sub": "user123",
  "name": "John Doe",
  "role": "admin",
  "iat": 1708275200,
  "exp": 1708361600
}

Server-side Code (Node.js with jsonwebtoken library):

javascriptCopyEditconst jwt = require('jsonwebtoken');

const user = { id: 'user123', name: 'John Doe', role: 'admin' };

// Secret Key (must be kept safe)
const secretKey = 'my_super_secret_key';

// Generate JWT
const token = jwt.sign(user, secretKey, { expiresIn: '1h' });

console.log('JWT Token:', token);

Response (JWT returned to the client):

jsonCopyEdit{
  "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}

Step 3: Client Stores and Uses the JWT

The client stores the JWT in:

  • LocalStorage: For browser-based apps.

  • SessionStorage: For short-lived sessions.

  • HTTP-only cookies: For better security.

Example Header for Authenticated Requests:

hCopyEditGET /api/protected-resource
Authorization: Bearer <JWT_TOKEN>

Step 4: Server Validates the JWT

Upon receiving a protected request, the server verifies the JWT.

JWT Verification Code (Node.js):

javascriptCopyEdit// Middleware to verify JWT
function authenticateToken(req, res, next) {
    const authHeader = req.headers['authorization'];
    const token = authHeader && authHeader.split(' ')[1];

    if (!token) return res.sendStatus(401);

    jwt.verify(token, secretKey, (err, user) => {
        if (err) return res.sendStatus(403);
        req.user = user;
        next();
    });
}

🛠️ How JWT Signature Verification Works

The server:

  1. Decodes the token (Header & Payload).

  2. Recomputes the signature with the same algorithm and secret key.

  3. Compares it with the received signature.

  4. If it matches, the token is valid.

Pros of Using JWT

1. Stateless Authentication

  • No need for a session store; tokens contain all required information.

  • Useful for microservices and distributed systems.

2. Compact and Fast

  • JWTs are small in size and can be easily transmitted via HTTP headers.

  • They perform well in web and mobile applications.

3. Secure Data Transmission

  • JWTs are signed, ensuring data integrity and preventing tampering.

  • When encrypted (JWE), they provide confidentiality.

4. Cross-Domain Authentication

  • JWTs work seamlessly with Single Sign-On (SSO) systems across multiple domains.

Cons of Using JWT

1. Cannot Be Revoked Easily

  • Once issued, a JWT remains valid until expiration.

  • If stolen, an attacker can use it until the token expires.

2. Larger Than Traditional Session Tokens

  • If the payload contains too much data, JWTs can become large, impacting performance.

3. Risk of Token Theft

  • If an attacker gains access to a JWT, they can impersonate the user and perform malicious actions.

4. No Built-in Key Rotation

  • Changing signing keys requires careful implementation to avoid breaking authentication.

Security Risks: If a JWT Is Hacked, the Hacker Can Act on Your Behalf

Imagine giving someone a signed check—if they copy it, they can withdraw money until the bank notices. One of the biggest risks with JWT is that if an attacker obtains a valid token, they can impersonate the user and make API requests on their behalf. Unlike session-based authentication, JWTs do not have a central session store where tokens can be invalidated in real-time.

Example Attack Scenarios:

  • Token Theft via XSS (Cross-Site Scripting): If a JWT is stored in localStorage, an attacker can steal it using malicious scripts.

  • Man-in-the-Middle (MITM) Attacks: If JWTs are transmitted over an insecure HTTP connection, they can be intercepted.

  • Token Replay Attacks: If the same JWT is reused multiple times, an attacker can gain persistent unauthorized access.


Best Practices for Securing JWT

1. Use Short-Lived Access Tokens & Refresh Tokens

  • Set a short expiration time (exp claim) for access tokens (e.g., 15 minutes).

  • Use refresh tokens stored securely in httpOnly cookies.

  • Invalidate refresh tokens if suspicious activity is detected.

2. Secure Token Storage

  • DO NOT store JWTs in localStorage or sessionStorage (prone to XSS attacks).

  • Use httpOnly, secure, and SameSite=strict cookies to store tokens.

3. Implement Token Blacklisting

  • Maintain a server-side revocation list to block compromised tokens.

  • Implement token versioning so that updating a user’s session invalidates old tokens.

4. Use Strong Secret Keys and Signing Algorithms

  • Use RS256 (asymmetric key signing) instead of HS256 (symmetric key signing) for better security.

  • Store private keys securely using AWS KMS, Azure Key Vault, or Google Cloud KMS.

5. Validate JWT Signature, Issuer, and Audience

  • Ensure tokens are signed by your trusted authentication server.

  • Validate the issuer (iss) and audience (aud) fields to prevent accepting forged tokens.

6. Use HTTPS Everywhere

  • Always serve your application over HTTPS to prevent token interception.

  • Implement HSTS (HTTP Strict Transport Security) to enforce secure connections.

7. Implement Token Binding (Device-Specific Tokens)

  • Bind JWTs to specific user attributes (e.g., IP, device fingerprint, User-Agent).

  • Revoke tokens if access is attempted from an unknown source.

8. Monitor and Log API Access

  • Log authentication attempts and API requests.

  • Detect anomalies like multiple logins from different locations in a short time.

9. Require Reauthentication for Critical Actions

  • Force users to reauthenticate for sensitive actions (e.g., password change, money transfer).

10. Use OAuth2 with JWT for Enhanced Security

  • Instead of using only JWT, integrate OAuth2 flows (PKCE, implicit flow) to enhance security.

  • Use scopes and permissions to control token access levels.


Conclusion

JWTs are a powerful tool for authentication and authorization in modern web applications, but they come with security risks. If an attacker steals a JWT, they can act on behalf of the user until the token expires.

By following best practices such as short-lived tokens, secure storage, strong encryption, HTTPS enforcement, and token blacklisting, you can significantly reduce the risks associated with JWTs and make your application more secure.

0
Subscribe to my newsletter

Read articles from Prashant Bale directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Prashant Bale
Prashant Bale

With 17+ years in software development and 14+ years specializing in Android app architecture and development, I am a seasoned Lead Android Developer. My comprehensive knowledge spans all phases of mobile application development, particularly within the banking domain. I excel at transforming business needs into secure, user-friendly solutions known for their scalability and durability. As a proven leader and Mobile Architect.