JWT Authentication — Complete JSON Web Token Guide
In this tutorial, you will learn about JWT Authentication. We cover key concepts, practical examples, and best practices to help you master this topic.
JSON Web Token (JWT) authentication is the most common token-based auth pattern. JWTs contain JSON claims signed by the issuer, allowing any service with the verification key to authenticate users without database lookups.
What You'll Learn
You'll learn JWT structure, signing algorithms, security best practices, and common implementation patterns.
Why It Matters
JWT powers authentication for millions of APIs including Google, Microsoft, Auth0, and Firebase. Understanding JWT is essential for modern API development.
Real-World Use
A SaaS platform issues JWTs upon login. Each microservice validates tokens locally using a cached public key. This eliminates the need for a centralized session store and reduces authentication latency to microseconds.
flowchart LR
A[JWT Token] --> B[Header: alg, typ]
A --> C[Payload: sub, exp, iat, role]
A --> D[Signature: verified with key]
B --> E[Base64 Encode]
C --> E
E --> F[Sign with Secret/Key]
F --> G[Base64URL Encode]
G --> H[Final JWT: xxx.yyy.zzz]
Teacher's Mindset
A JWT is like a passport. The passport has your photo and info (payload), the issuing country's stamp (signature), and an expiration date. Any immigration officer can verify it without calling the issuing country.
Implementation
import jwt
from datetime import datetime, timedelta
import secrets
PRIVATE_KEY = """-----BEGIN RSA PRIVATE KEY-----
...your private key...
-----END RSA PRIVATE KEY-----"""
PUBLIC_KEY = """-----BEGIN PUBLIC KEY-----
...your public key...
-----END PUBLIC KEY-----"""
def create_jwt(subject, extra_claims=None):
claims = {
"sub": subject,
"iss": "auth.example.com",
"aud": "api.example.com",
"iat": datetime.utcnow(),
"exp": datetime.utcnow() + timedelta(minutes=15),
"jti": secrets.token_hex(16)
}
if extra_claims:
claims.update(extra_claims)
return jwt.encode(claims, PRIVATE_KEY, algorithm="RS256")
def verify_jwt(token):
try:
payload = jwt.decode(
token,
PUBLIC_KEY,
algorithms=["RS256"],
audience="api.example.com",
issuer="auth.example.com",
options={"require": ["sub", "exp", "iat", "jti"]}
)
return payload
except jwt.InvalidTokenError as e:
raise ValueError(f"Invalid token: {e}")
token = create_jwt("user_123", {"role": "admin"})
print(f"Token: {token[:50]}...")
payload = verify_jwt(token)
print(f"Subject: {payload['sub']}, Role: {payload['role']}")
Common Mistakes
| Mistake | Fix |
|---|---|
| Using HS256 in Microservices | Shared secret must be distributed; use RS256 |
| Not validating all required claims | Check sub, exp, iat, jti, aud, iss |
| Algorithm confusion vulnerability | Explicitly set algorithms in decode |
| Self-contained tokens too large | Minimize payload; use reference tokens for large data |
| Not using JTI for revocation | Store JTI in a short-lived blocklist if revocation needed |
Practice Questions
- What three parts make up a JWT?
- Why is RS256 preferred over HS256 for microservices?
- What is the purpose of the JTI claim?
- How do you handle JWT revocation?
- What is the maximum recommended JWT payload size?
Challenge
Implement JWT authentication with RS256. Create an auth service that issues tokens and a resource service that validates them. Include JTI-based revocation. Test with valid, expired, and revoked tokens.
What's Next
Learn about JWT access and refresh token pattern for secure session management.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro