JWT Authentication Security
# 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.
Header (aaaaa): Contains metadata, usually the type (
JWT) and the hashing algorithm used (e.g.,HS256).
-
2.
Payload (bbbbb): The actual data (claims) you are transmitting (e.g.,
{"user_id": 123, "role": "admin"}).
- 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):
Secure PHP (Using a vetted library like firebase/php-jwt):
7. JSON Examples (The Payload)
A standard JWT payload contains registered "claims" (standardized fields):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
/refreshendpoint 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
.envfile.
-
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.
Copy a JWT from your own testing or use
jwt.ioto generate one. Paste it into the debugger atjwt.ioand look at the decoded payload.
- 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
Are the Header and Payload sections of a standard JWT encrypted and hidden from the public?
What is the primary purpose of the "Signature" section of a JWT?
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 inlocalStorage 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.