Understanding JWT Tokens: A Complete Guide for Developers
Published March 2026 · 10 min read
What is JWT and Why Does It Matter?
JSON Web Token (JWT) is an open standard defined in RFC 7519 that provides a compact, URL-safe way to represent claims between two parties. Since its formal specification in 2015, JWT has become one of the most widely adopted authentication and authorization mechanisms on the web. If you have ever logged into a modern web application, there is a good chance a JWT was involved behind the scenes.
JWTs solve a fundamental problem in distributed systems: how do you prove who you are without the server having to look you up in a database on every single request? Instead of maintaining server-side sessions, a JWT encodes all the necessary information directly into the token itself. The server can verify the token's integrity using a cryptographic signature, eliminating the need for a centralized session store.
This guide walks you through every aspect of JWT — from the raw structure of the token to real-world authentication flows, security pitfalls, and best practices that will help you use JWTs confidently in production.
JWT Structure
A JWT is a single string composed of three Base64URL-encoded segments separated by dots. Each segment serves a distinct purpose:
header.payload.signatureHere is what an actual JWT looks like in the wild:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5cAt first glance it looks like random gibberish, but each colored section decodes into readable JSON (or binary data for the signature). Let's break down each part.
Header
The header is a small JSON object that describes how the token is signed. It typically contains two fields:
alg— the signing algorithm (e.g.,HS256,RS256)typ— the token type, almost alwaysJWT
{
"alg": "HS256",
"typ": "JWT"
}This JSON is then Base64URL-encoded to produce the first segment of the token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.
Common Signing Algorithms
| Algorithm | Type | Description |
|---|---|---|
| HS256 | Symmetric | HMAC with SHA-256. A single shared secret is used to both sign and verify the token. Simple and fast, ideal for single-server setups. |
| RS256 | Asymmetric | RSA with SHA-256. Uses a private key to sign and a public key to verify. Preferred for distributed systems where multiple services need to verify tokens. |
| ES256 | Asymmetric | ECDSA with SHA-256. Similar to RS256 but uses elliptic curve cryptography, resulting in smaller keys and faster operations. |
Payload (Claims)
The payload is the heart of the JWT. It contains claims — statements about the user and additional metadata. Claims are simply key-value pairs in a JSON object.
Registered Claims
The JWT specification defines a set of standard claims. None of them are mandatory, but they are widely recognized and recommended:
| Claim | Full Name | Description |
|---|---|---|
| iss | Issuer | Identifies who issued the token (e.g., your auth server URL). |
| sub | Subject | Identifies the principal subject of the token, typically a user ID. |
| aud | Audience | Identifies the intended recipients of the token. Reject tokens not meant for your service. |
| exp | Expiration Time | Unix timestamp after which the token is no longer valid. Always set this. |
| nbf | Not Before | Unix timestamp before which the token must not be accepted. |
| iat | Issued At | Unix timestamp when the token was created. Useful for calculating token age. |
| jti | JWT ID | A unique identifier for the token. Prevents replay attacks when combined with server-side tracking. |
Public and Private Claims
Beyond the registered claims, you can add your own. Public claims should be registered in the IANA JSON Web Token Claims registry or use collision-resistant names (like URIs). Private claims are custom claims agreed upon between the producer and consumer — for example, role or team_id.
Here is a complete payload example:
{
"iss": "https://auth.example.com",
"sub": "user_8a3b9c",
"aud": "https://api.example.com",
"exp": 1772380800,
"iat": 1772377200,
"nbf": 1772377200,
"jti": "unique-token-id-abc123",
"role": "admin",
"name": "Jane Doe"
}Warning: The payload is only Base64URL-encoded, not encrypted. Anyone who obtains the token can decode and read the payload. Never place passwords, credit card numbers, or other secrets in a JWT payload.
Signature
The signature is the mechanism that guarantees the token has not been tampered with. It is created by taking the encoded header, the encoded payload, a secret (or private key), and the algorithm specified in the header:
HMACSHA256(
base64UrlEncode(header) + "." + base64UrlEncode(payload),
secret
)When using an asymmetric algorithm like RS256, the process is similar but the signing uses a private key while verification uses the corresponding public key:
RSASHA256(
base64UrlEncode(header) + "." + base64UrlEncode(payload),
privateKey
)Key distinction: The signature provides integrity, not confidentiality. It proves the token was not altered after being issued, but it does not hide the contents. If you need encrypted tokens, look into JWE (JSON Web Encryption).
HMAC vs RSA Signing
With HMAC (symmetric), the same secret key is used to create and verify the signature. This is simple and fast, but every service that needs to verify the token must possess the secret. If that secret leaks from any one service, every token can be forged.
With RSA (asymmetric), only the authentication server holds the private key. All other services verify tokens using the public key, which can be freely distributed. Even if a verification service is compromised, the attacker cannot forge new tokens because they lack the private key.
How JWT Authentication Works
Here is the typical flow of JWT-based authentication in a web application:
User Logs In
The user sends their credentials (username + password) to the authentication server via a login endpoint.
Server Creates JWT
After validating the credentials, the server creates a JWT containing the user's ID, roles, and an expiration time. It signs the token with a secret key and returns it in the response.
Client Stores Token
The client stores the JWT — typically in memory, an HTTP-only cookie, or (less ideally) localStorage. The storage choice has significant security implications.
Client Sends Token with Requests
For every subsequent API call, the client includes the JWT in the Authorization header: Bearer <token>
Server Verifies Token
The server extracts the JWT, verifies the signature, checks the expiration, and reads the claims. If everything checks out, the request is authorized without any database lookup.
This stateless approach means the server does not need to maintain session data in memory or a database. Each request is self-contained — the JWT carries all the information needed to authenticate and authorize the user.
Think of a JWT like a concert ticket with a tamper-proof holographic seal. The bouncer (server) doesn't need to call the box office (database) for every person — they just verify the seal is intact and the date is valid.
Common Use Cases
Authentication
This is by far the most common use of JWT. After a user logs in, every subsequent request includes the JWT, allowing the server to verify identity without maintaining sessions. This is particularly powerful for single-page applications (SPAs) and mobile apps that communicate with APIs.
Information Exchange
JWTs are a secure way to transmit information between parties. Because they can be signed (and optionally encrypted), the receiver can trust that the content has not been altered. Microservices frequently use JWTs to pass user context between internal services.
API Authorization
JWTs can encode permissions and scopes directly in the payload. An API gateway can check these claims to determine whether a request should be allowed without contacting the authorization server on every call. OAuth 2.0 access tokens are often issued as JWTs for this reason.
Single Sign-On (SSO)
JWT is widely used in SSO implementations. A user authenticates once with a central identity provider and receives a JWT. This token is then accepted by multiple applications across different domains, providing a seamless login experience without re-entering credentials.
Stateless Sessions
Traditional session management requires server-side storage (memory, database, or Redis). JWTs enable fully stateless sessions where all session data lives in the token itself. This simplifies horizontal scaling because any server instance can handle any request without shared session storage.
Security Best Practices
JWTs are powerful, but improper use can introduce serious security vulnerabilities. Follow these practices to keep your implementation secure:
- Always verify the signature. Never trust a JWT without first validating its signature using your secret or public key. Skipping verification is equivalent to accepting unsigned data from an untrusted source.
- Check expiration (
exp). Always validate that the token has not expired. Accepting expired tokens gives attackers a wider window to exploit stolen tokens. - Use HTTPS only. JWTs should only be transmitted over TLS/HTTPS. Sending tokens over plain HTTP exposes them to man-in-the-middle attacks. Set the
Secureflag on cookies. - Do not store sensitive data in the payload. Remember, anyone can decode the payload. Keep it limited to identifiers, roles, and metadata. Sensitive information belongs in your database, not your token.
- Use appropriate algorithms. Avoid
noneas an algorithm in production — this disables signature verification entirely. Prefer RS256 or ES256 for distributed systems, and always validate thealgheader matches what your server expects. - Set reasonable expiration times. Short-lived access tokens (5-15 minutes) combined with refresh tokens provide the best balance between usability and security. A token that lives for 30 days is a 30-day vulnerability window if stolen.
- Consider token revocation strategies. Since JWTs are stateless, there is no built-in way to revoke them before expiration. Consider maintaining a token blocklist for critical scenarios (user logout, password change, account compromise), or use short expiration times to minimize the revocation problem.
Common Vulnerability: The “alg confusion” attack occurs when an attacker changes the header algorithm from RS256 to HS256, then signs the token with the public key (which is publicly available). If the server does not restrict accepted algorithms, it may verify the token using the public key as an HMAC secret. Always whitelist allowed algorithms on the server side.
JWT vs Server-Side Sessions
Choosing between JWTs and traditional server-side sessions depends on your architecture and requirements. Here is a side-by-side comparison:
| Feature | JWT | Server-Side Sessions |
|---|---|---|
| Storage | Client-side (cookie, localStorage, memory) | Server-side (memory, database, Redis) |
| Scalability | Excellent — no shared state needed | Requires shared session store for multi-server |
| Revocation | Difficult — token valid until expiration | Easy — delete the session from the store |
| Payload Size | Larger — data embedded in token | Minimal — only session ID sent to client |
| Cross-Domain | Works easily across domains and services | Complex — cookies are domain-bound |
| Database Load | None for verification | Session lookup on every request |
| Security Risk | Token theft (XSS if in localStorage) | Session hijacking (CSRF if cookie-based) |
When to Use JWT
- Distributed microservices architecture where session sharing is impractical
- Single Sign-On (SSO) across multiple domains or applications
- Mobile applications communicating with REST APIs
- Serverless or edge computing where persistent storage is expensive
- Short-lived, stateless authorization grants
When to Use Sessions
- Single-server monolithic applications
- Applications requiring immediate session revocation
- When storing minimal data in the token is critical
- High-security environments where token exposure must be minimized
- Applications where users frequently change permissions in real-time
Hybrid approach: Many production systems combine both strategies. They use short-lived JWTs for API access tokens (valid for 5-15 minutes) alongside server-side refresh token sessions. This gives you the scalability benefits of JWTs with the revocation capability of server-side sessions.
Try It Yourself
The best way to internalize how JWTs work is to decode one yourself. Take the example token from earlier in this article, or grab a JWT from your own application, and paste it into our decoder tool to see the header, payload, and signature broken down in real time.
Decode Your JWT Tokens Instantly
Paste any JWT to inspect its header, payload, and claims. Everything runs in your browser — your tokens never leave your machine.
Open JWT Decoder