Key Takeaways
- What is a JWT? A self-contained token encoding user identity and claims, signed so the server can verify it without looking up a database session.
- Three parts: Header (algorithm), Payload (claims/data), Signature (cryptographic proof of authenticity).
- Key advantage: Stateless — the server does not need to store sessions. Works well for APIs and microservices.
- Key limitation: Cannot be invalidated before expiry without additional server-side infrastructure.
If you have ever logged into a web app and made API calls after that, you have almost certainly used JWTs. JSON Web Tokens are the dominant authentication mechanism for modern APIs and single-page applications. They are elegant in their design and straightforward to understand once you see the structure — but they are also commonly misimplemented in ways that create real security vulnerabilities.
This guide explains JWTs clearly, covers the full authentication flow, and walks through the security decisions that separate good implementations from bad ones.
What Is a JWT?
A JWT (JSON Web Token) is a compact, self-contained string that encodes a set of claims — pieces of information about a user or entity — along with a cryptographic signature that proves the token is authentic and unmodified.
A JWT looks like this:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOiIxMjM0NTYiLCJlbWFpbCI6InVzZXJAZXhhbXBsZS5jb20iLCJpYXQiOjE2ODE2MTEyMDAsImV4cCI6MTY4MTYxNDgwMH0.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
Three Base64-encoded sections separated by dots. You can paste any JWT at jwt.io and decode the contents — they are not encrypted by default, just encoded.
The key point: JWTs are self-contained. The server does not need to look up anything in a database to verify a JWT. It reads the token, verifies the signature, checks the expiration, and knows who you are. This statelessness is the primary advantage of JWTs over server-side sessions.
The Three Parts of a JWT
Learn the Core Concepts
Start with the fundamentals before touching tools. Understanding why something was built the way it was makes every tool decision faster and more defensible.
Build Something Real
The fastest way to learn is to build a project that produces a real output — something you can show, share, or deploy. Toy examples teach you the happy path; real projects teach you everything else.
Know the Trade-offs
Every technology choice is a trade-off. The engineers who advance fastest are the ones who can articulate clearly why they chose one approach over another — not just "I used it before."
Go to Production
Development is the easy part. The real learning happens when you deploy, monitor, debug, and scale. Plan for production from day one.
Every JWT has three sections: Header, Payload, and Signature — each separated by a period and Base64URL-encoded.
Header
The header specifies the token type and the signing algorithm:
{
"alg": "HS256",
"typ": "JWT"
}
HS256 means HMAC-SHA256 — a symmetric signing algorithm using a shared secret. RS256 uses RSA with a public/private key pair. The algorithm choice matters for security.
Payload
The payload contains the claims — the actual data in the token:
{
"userId": "123456",
"email": "[email protected]",
"role": "admin",
"iat": 1681611200,
"exp": 1681614800
}
Standard claims include iat (issued at time), exp (expiration time), and sub (subject — usually user ID). You can add any custom claims. Do not put sensitive information like passwords or credit card numbers in the payload — it is encoded, not encrypted, and can be read by anyone who has the token.
Signature
The signature is computed as:
HMACSHA256(base64(header) + "." + base64(payload), secret)
The server signs the header and payload with a secret key. When it receives a JWT, it recomputes the signature from the header and payload and checks that it matches. If someone modifies even one character of the payload (for example, changing their role from "user" to "admin"), the signature check fails and the token is rejected.
How the Signature Works
The signature is the entire security foundation of a JWT. It prevents tampering — but it does not prevent reading.
Remember: the payload is Base64-encoded, not encrypted. Anyone who intercepts the token can decode and read the payload. The signature only proves that the token was issued by someone who had the secret key and that the content has not been changed since it was issued.
This distinction matters for what you put in the payload. Sensitive data (anything you would not want intercepted in transit) should not go in a JWT payload unless you are also using HTTPS consistently (which you should be for any production application anyway) or using JWE (JSON Web Encryption, which is a separate standard that actually encrypts the payload).
The JWT Authentication Flow
Here is the complete flow from login to authenticated API request.
- User logs in. They submit their username and password to the authentication endpoint (
POST /auth/login). - Server verifies credentials. The server checks the database, verifies the password hash, and if correct, generates a JWT signed with the server's secret key.
- Server returns the JWT. The token is sent back in the response body or as a cookie. The client stores it (in memory, localStorage, or a cookie — each has security trade-offs).
- Client sends JWT with requests. For authenticated requests, the client includes the JWT in the Authorization header:
Authorization: Bearer eyJ... - Server verifies the JWT. On each request, the server extracts the token, verifies the signature, checks that it has not expired, and extracts the user identity from the payload.
- No database lookup needed. The server knows who you are from the verified token alone. This is the statelessness advantage.
JWT vs Session Cookies
Traditional session-based auth stores a session ID in a database on the server and sends it to the client as a cookie. JWT moves all the state into the token itself, eliminating server-side session storage.
Session advantages over JWT:
- Immediate revocation — delete the session row, access is denied instantly
- No token size concerns — session ID is tiny; large JWTs can affect request overhead
- Lower XSS risk — httpOnly cookies cannot be read by JavaScript
JWT advantages over sessions:
- Stateless — scales horizontally without a shared session store
- Works across domains — not limited by cookie same-origin policies
- Self-contained — microservices can verify identity without calling a central auth service
- Works naturally for mobile and API clients
Common JWT Security Mistakes
Most JWT security incidents come from a small set of known implementation mistakes.
- Storing JWTs in localStorage: localStorage is accessible to any JavaScript on the page, making it vulnerable to XSS attacks. Prefer httpOnly cookies for web apps or in-memory storage with short expiration.
- Not validating the signature: Some early libraries had a bug where passing algorithm "none" skipped signature verification. Always verify signatures and always enforce which algorithm you accept.
- Weak secrets: HS256 with a short, guessable secret is crackable. Use cryptographically random secrets of at least 256 bits.
- No expiration: Tokens without expiration are valid forever if compromised. Always set
exp. Short-lived tokens (15-60 minutes) with refresh tokens is the standard pattern. - Sensitive data in payload: The payload is readable by anyone. Do not store passwords, PII, or secrets in the payload.
- Not validating claims: Verify
exp,iss(issuer), andaud(audience) in addition to the signature. A valid signature on an expired token or a token for a different service should still be rejected.
JWT Best Practices
- Use short access token expiration (15-60 minutes) with refresh tokens for a better security/UX balance
- Store tokens in httpOnly, Secure, SameSite cookies for web applications
- Enforce your expected signing algorithm server-side — do not trust the header's
algvalue - Use RS256 (asymmetric) rather than HS256 (symmetric) when multiple services need to verify tokens
- Validate all standard claims: expiration, issuer, audience
- Keep payloads small — put only what you need for authorization decisions
- Implement a token blocklist for critical revocation scenarios (logout, password change)
Build secure AI applications from scratch. In person.
The Precision AI Academy bootcamp covers auth, APIs, and production AI systems. $1,490. Two days. October 2026.
Reserve Your SeatFrequently Asked Questions
What is a JWT?
A JWT (JSON Web Token) is a compact, self-contained token that encodes a set of claims about a user or entity, signed with a secret key or asymmetric key pair. It authenticates API requests: the server issues a JWT after login, and the client sends it with subsequent requests to prove identity without the server needing to look up a session in a database.
What are the three parts of a JWT?
A JWT has three parts separated by dots: Header.Payload.Signature. The Header specifies the token type and signing algorithm. The Payload contains the claims — data like user ID, email, role, and expiration time. The Signature is a cryptographic hash that proves the token has not been tampered with.
Is JWT secure?
JWTs are secure when implemented correctly. The signature prevents tampering. However, common mistakes make JWTs insecure: storing them in localStorage, not validating the signature, using weak secrets, not setting expiration times, or putting sensitive data in the payload (which is encoded, not encrypted).
Can you invalidate a JWT before it expires?
Not natively — this is one of JWT's limitations. A JWT is valid until it expires regardless of server-side state. Solutions include: using short expiration times, maintaining a token blocklist for critical revocation cases, or using refresh tokens with short-lived access tokens.
When should I use JWT versus session cookies?
Use JWTs for stateless API authentication, microservices, and mobile applications. Use session cookies for traditional server-rendered web applications where you need immediate token revocation and are concerned about XSS (httpOnly cookies cannot be read by JavaScript).