JWT Tokens Explained — Understanding JSON Web Tokens
JSON Web Tokens Explained — How Modern Authentication Actually Works
When you log into a web application, something needs to happen so that the server recognizes you on your next request. In the early web, servers stored a session file and gave your browser a session ID cookie — every request included this ID, and the server looked up your session to know who you were. This works but does not scale well: every server in a cluster needs access to the session store, and millions of concurrent sessions require significant memory.
JSON Web Tokens (JWTs) solve this by flipping the model: instead of the server storing your session, the server gives you a signed token containing your identity information. On subsequent requests, you send this token back, and the server verifies its signature to confirm it is authentic — without looking anything up in a database.
The Structure of a JWT
A JWT consists of three parts separated by dots: header.payload.signature
Header: A Base64-encoded JSON object specifying the token type and signing algorithm. Typically: {"alg": "HS256", "typ": "JWT"}
Payload: A Base64-encoded JSON object containing claims — key-value pairs with information about the user and the token. Standard claims include sub (subject — the user ID), exp (expiration time), iat (issued at), and iss (issuer). You can add custom claims like role, email, or permissions.
Signature: Created by signing the encoded header and payload with a secret key using the specified algorithm. The server that created the token knows the secret key and can verify that the token has not been tampered with. If anyone modifies the payload (for example, changing their role from “user” to “admin”), the signature verification fails and the server rejects the token.
The Authentication Flow
- User sends login credentials (username/password) to the server
- Server verifies credentials against the database
- If valid, server creates a JWT containing the user’s ID and permissions, signs it with a secret key, and sends it back
- Client stores the JWT (typically in localStorage or an httpOnly cookie)
- On every subsequent request, client includes the JWT in the Authorization header
- Server verifies the JWT signature and extracts user information from the payload — no database lookup needed
Why JWTs Scale Better Than Sessions
In a session-based system with 10 servers behind a load balancer, a session created on Server 1 is not automatically available on Server 2. You need sticky sessions (routing users to the same server, which reduces load balancing effectiveness) or a shared session store (Redis or database, which adds infrastructure complexity and a single point of failure).
With JWTs, any server can verify any token because they all share the same signing key. The token itself contains all the information the server needs. No shared state, no session store, no sticky sessions. Each server is independently capable of authenticating any request.
JWT Security Considerations
Never store sensitive data in the payload: The payload is Base64-encoded, not encrypted. Anyone who intercepts the token can decode and read the payload. Include only identification information (user ID, role), never passwords, API keys, or personal data.
Set short expiration times: JWTs cannot be individually revoked like sessions (there is no server-side record to delete). If a token is stolen, it remains valid until it expires. Short expiration (15 minutes to 1 hour for access tokens) limits the damage window. Use refresh tokens with longer expiration for renewing access tokens.
Always use HTTPS: JWTs transmitted over unencrypted HTTP can be intercepted and used by attackers. HTTPS prevents this interception.
Decode and inspect JWTs with our developer tools — paste a token to see its header, payload, and verify whether it has expired.