Skip to main content
API Security Tutorial
CHAPTER 06 Intermediate

JWT Authentication Security

Updated: May 13, 2026
25 min read

# CHAPTER 6

JWT Authentication Security

1. Introduction

JSON Web Tokens (JWT) have become the industry standard for securing modern REST APIs and Single Page Applications (SPAs). Unlike traditional sessions, JWTs are stateless, meaning the backend doesn't need to query the database to verify a user on every single request. However, this immense power comes with massive security responsibilities. If implemented incorrectly, JWTs can easily be forged or hijacked. In this chapter, we will dissect the anatomy of a JWT, explore common vulnerabilities like the "none" algorithm attack, and learn how to securely generate and validate tokens in PHP.

2. Learning Objectives

By the end of this chapter, you will be able to:
  • Understand the three-part structure of a JSON Web Token.
  • Explain the difference between Base64 encoding (readable) and Hashing (secure).
  • Identify and mitigate critical JWT vulnerabilities (e.g., algorithm switching).
  • Understand the necessity of Token Expiration and Refresh Tokens.
  • Implement secure JWT generation and validation in PHP.

3. Beginner-Friendly Explanation

Imagine a VIP wristband at a music festival.
  • When you first arrive, you show your ID (Email/Password) at the gate.
  • The gate attendant gives you a glowing wristband (The JWT).
  • The wristband has information printed on it: "John Doe, VIP, Expires at Midnight."
  • As you walk around the festival, you show the wristband to enter different VIP tents. The tent guards don't need to call the front gate to check your ID; they just look at the wristband.

The crucial part: How do the tent guards know you didn't just print the wristband yourself? The wristband contains a cryptographic signature—a special glowing stamp that only the festival organizers (the Server) have the ink for. If a hacker alters the text on the wristband from "General Admission" to "VIP", the glowing stamp breaks, and the guard immediately rejects it.

4. Real-World Attack Scenarios

  • The "None" Algorithm Attack: Early JWT libraries had a flaw. A hacker could take a valid token, change their user ID to 1 (Admin), and change the token's encryption algorithm to "none". The server would see "none", decide it didn't need to verify the signature, and grant the hacker Admin access.
  • Secret Key Brute Forcing: If a developer uses a weak secret key (like secret123) to sign the JWT, a hacker can easily guess the key offline, and then forge unlimited valid tokens for any user.

5. JWT Structure (Anatomy of a Token)

A JWT looks like a long string of gibberish, separated by two periods: aaaaa.bbbbb.ccccc
  1. 1. Header (aaaaa): Contains metadata, usually the type (JWT) and the hashing algorithm used (e.g., HS256).
  1. 2. Payload (bbbbb): The actual data (claims) you are transmitting (e.g., {"user_id": 123, "role": "admin"}).
  1. 3. Signature (ccccc): The mathematical hash of the Header + Payload + Your Server's Secret Key.

*CRITICAL WARNING:* The Header and Payload are merely Base64 encoded, NOT encrypted. Anyone who intercepts the token can decode it and read the JSON payload. Never put passwords or credit card numbers in a JWT payload!

6. Vulnerable vs Secure Code Examples

Vulnerable PHP (Trusting the payload without verifying the signature):

php
12345678910
<?php
$token = $_SERVER[&#039;HTTP_AUTHORIZATION'];
$parts = explode(&#039;.', $token);
// DANGER: Decoding the payload and trusting it without verifying the signature!
$payload = json_decode(base64_decode($parts[1])); 

if ($payload->role === &#039;admin') {
    grant_admin_access(); // Hacker just gave themselves admin access.
}
?>

Secure PHP (Using a vetted library like firebase/php-jwt):

php
12345678910111213141516171819
<?php
use Firebase\JWT\JWT;
use Firebase\JWT\Key;

$token = str_replace(&#039;Bearer ', '', $_SERVER['HTTP_AUTHORIZATION']);
$secret_key = $_ENV[&#039;JWT_SECRET']; // A strong, 64-character random string

try {
    // This library automatically checks the signature and the expiration date!
    $decoded = JWT::decode($token, new Key($secret_key, &#039;HS256'));
    
    if ($decoded->role === &#039;admin') {
        grant_admin_access();
    }
} catch (Exception $e) {
    http_response_code(401);
    echo json_encode(["error" => "Invalid or expired token."]);
}
?>

7. JSON Examples (The Payload)

A standard JWT payload contains registered "claims" (standardized fields):
json
123456
{
  "iss": "https://api.mybank.com", // Issuer
  "sub": "1234567890",             // Subject (User ID)
  "exp": 1716336000,               // Expiration Time (Unix Timestamp)
  "role": "user"                   // Custom claim
}

8. Token Expiration and Refresh Tokens

Because JWTs are stateless, the server cannot easily "delete" them. If a hacker steals a JWT, they have access until it expires.
  • Rule: Access Tokens must have a short lifespan (e.g., 15 minutes to 1 hour).
  • Refresh Tokens: When the short-lived Access Token expires, the client sends a long-lived "Refresh Token" to a special /refresh endpoint to get a new Access Token. Unlike JWTs, Refresh Tokens are saved in the database, allowing the server to revoke them instantly if a user's account is compromised.

9. Best Practices

  • Use a Vetted Library: Never write your own JWT verification code. The cryptographic math is complex and highly prone to timing attacks. Use industry-standard libraries like firebase/php-jwt.
  • Strong Secrets: Generate your JWT Secret Key using a CSPRNG (like we did in Chapter 5) and store it securely in your .env file.
  • Validate the Algorithm: Ensure your verification code explicitly demands a specific algorithm (e.g., HS256). Do not let the token itself dictate the algorithm.

10. Common Mistakes

  • Storing Sensitive Data: Putting personal identifiable information (PII) like home addresses or social security numbers in the JWT payload. Anyone who gets the token can read it.
  • Infinite Lifespans: Creating a JWT that does not contain an exp (expiration) claim, or setting the expiration to 10 years in the future.

11. Mini Exercises

  1. 1. Copy a JWT from your own testing or use jwt.io to generate one. Paste it into the debugger at jwt.io and look at the decoded payload.
  1. 2. Why is it dangerous to trust the data in the Payload without verifying the Signature?

12. Practice Challenges

Challenge: Assume an attacker intercepts a JWT that says {"role": "user"}. The attacker uses Base64 encoding to change the payload to {"role": "admin"} and sends it back to the server. Explain exactly how the server's cryptographic Signature verification process will detect this tampering.

13. MCQs with Answers

Question 1

Are the Header and Payload sections of a standard JWT encrypted and hidden from the public?

Question 2

What is the primary purpose of the "Signature" section of a JWT?

Question 3

Because stateless JWTs cannot be easily revoked before they expire, what is the best practice for token lifespans?

14. Interview Questions

  • Q: What is the "None Algorithm" attack against JWTs, and how do you prevent it?
  • Q: Why shouldn't you store sensitive data (like a credit card number) in a standard JWT payload?
  • Q: Explain the architecture of using short-lived Access Tokens coupled with long-lived Refresh Tokens. Why not just use one long-lived Access Token?

15. FAQs

Q: Where should the frontend store the JWT? A: Storing it in localStorage makes it vulnerable to Cross-Site Scripting (XSS) attacks. The most secure place to store a JWT for web applications is in an HttpOnly, Secure cookie, as JavaScript cannot access it.

16. Summary

In this chapter, we conquered the industry standard for stateless API authentication: JSON Web Tokens. We broke down the three parts of a JWT (Header, Payload, Signature) and emphasized that payloads are easily readable, not encrypted. We learned that the Signature is the cryptographic shield that prevents tampering, and we discussed critical best practices: using strong secret keys, enforcing strict token expiration times, and always relying on vetted libraries rather than custom math.

17. Next Chapter Recommendation

JWTs are excellent for logging into your own API. But what if you want to let a user "Log in with Google"? Proceed to Chapter 7: OAuth 2.0 Security Basics to understand secure, federated identity.

Finish this Chapter

Save your progress on your learning path and prepare for coding interview challenges.

Discussion

Join the discussion

Log in or create a free account to participate.

Sort: ·