If you've worked on any modern web application, you've almost certainly encountered JWTs. Those long strings with three sections separated by dots — eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxMjM0NTY3ODkwIn0.abc123def — are everywhere: in your browser's cookies, in API request headers, and in mobile app authentication flows.
But what exactly is a JWT? How does it work under the hood? And what are the security implications of using it? This guide answers all of these questions with clear explanations and practical examples.
What Is a JWT?
JWT (JSON Web Token) is an open standard (RFC 7519) for securely transmitting information between parties as a JSON object. It's compact, URL-safe, and self-contained — meaning it carries all the necessary information about the user within itself.
JWTs are most commonly used for:
- Authentication — After a user logs in, the server issues a JWT. The client includes it in subsequent requests to prove identity.
- Authorization — The JWT contains claims about what the user is allowed to do (roles, permissions).
- Information Exchange — Parties can securely transmit verified information using JWT's signature mechanism.
The Structure of a JWT
A JWT consists of three parts, separated by dots (.):
1. Header
The header identifies the token type and the signing algorithm:
This JSON is base64url-encoded to form the first part of the JWT.
2. Payload
The payload contains the claims — statements about the entity (usually the user) and additional metadata:
There are three types of claims:
- Registered claims: Predefined claims like
iss(issuer),sub(subject),aud(audience),exp(expiration),iat(issued at), andjti(unique ID). - Public claims: Custom claims defined by you, using collision-resistant names (e.g., namespaced with a URI).
- Private claims: Custom claims for sharing information between parties that agree on using them.
3. Signature
The signature is created by combining the encoded header, encoded payload, a secret key, and the algorithm specified in the header:
The signature ensures the token hasn't been tampered with. If anyone modifies the header or payload, the signature won't match, and the server will reject the token.
How JWT Authentication Works
Here's the typical flow of JWT-based authentication:
- User logs in with their credentials (username/password).
- Server verifies credentials and creates a JWT containing the user's ID, role, and an expiration time.
- Server sends the JWT back to the client.
- Client stores the JWT (in a cookie, localStorage, or memory) and includes it in the
Authorizationheader of subsequent requests. - Server verifies the JWT signature on each request and extracts the user information.
- When the token expires, the client must obtain a new one (either by re-authenticating or using a refresh token).
JWT Signing Algorithms
The algorithm specified in the header determines how the signature is created. Understanding the differences is critical for security:
Symmetric Algorithms (HMAC)
- HS256 (HMAC + SHA-256) — Most common, same secret used for signing and verification.
- HS384 (HMAC + SHA-384)
- HS512 (HMAC + SHA-512)
With HMAC, the same secret key is used to both create and verify the signature. This means both the authentication server and the resource server must share the same secret.
Asymmetric Algorithms (RSA / ECDSA)
- RS256 (RSA + SHA-256) — Uses a private key to sign and a public key to verify.
- RS384 (RSA + SHA-384)
- RS512 (RSA + SHA-512)
- ES256 (ECDSA + P-256 + SHA-256) — More compact signatures than RSA.
- ES384 (ECDSA + P-384 + SHA-384)
- ES512 (ECDSA + P-521 + SHA-512)
Asymmetric algorithms are ideal when you have a separate authentication service: the auth service signs with a private key, and any service can verify with the public key. This is how OAuth providers like Google and Auth0 work.
Decoding a JWT
Since the header and payload are just base64url-encoded, you can decode them without any key:
This is why you should never store sensitive information in a JWT — anyone with the token can read the payload.
Want to inspect a JWT right now? Try our free JWT Decoder tool — paste any token and instantly see its header, payload, and signature details.
JWT vs Session-Based Authentication
Understanding when to use JWT vs traditional sessions helps you make the right architectural decision:
- Session-based: The server stores session data (in memory, Redis, or a database) and sends a session ID cookie to the client. The server looks up the session on each request.
- JWT-based: The token contains all necessary data. The server doesn't need to store anything — it just verifies the signature.
| Aspect | Sessions | JWT |
|---|---|---|
| Server Storage | Required (memory/Redis/DB) | Not required (stateless) |
| Scalability | Requires shared session store | Naturally scalable |
| Mobile Friendly | Cookie management is complex | Easy — just send in header |
| Revocation | Easy — delete from store | Hard — token valid until expiry |
| Size | Small (session ID) | Larger (full payload) |
| Cross-Domain | Complex (CORS + cookies) | Simpler (Authorization header) |
JWT Security Best Practices
1. Use Strong Signing Algorithms
Always specify the algorithm explicitly when verifying tokens. The "alg: none" attack exploits servers that accept unsigned tokens. Never use the none algorithm in production.
2. Keep Expiration Short
Set short expiration times (15–30 minutes for access tokens) and use refresh tokens for longer sessions:
3. Store Tokens Securely
- Best: HttpOnly, Secure, SameSite cookies — immune to XSS theft via JavaScript.
- Acceptable: In-memory JavaScript variables — lost on page reload but safe from persistent XSS.
- Risky: localStorage — accessible to any JavaScript on the page, vulnerable to XSS.
4. Validate All Claims
Don't just verify the signature — also check the claims:
5. Use HTTPS Always
JWTs sent over HTTP can be intercepted by anyone on the network. Always serve your application over HTTPS to protect tokens in transit.
6. Don't Put Sensitive Data in the Payload
Since anyone can decode the payload with base64, treat it like plaintext. Never include passwords, Social Security numbers, API secrets, or financial data.
Common JWT Vulnerabilities
Algorithm Confusion Attack
An attacker changes the alg header from RS256 to HS256. If the server uses the public RSA key as the HMAC secret (which some implementations do), the attacker can forge valid tokens. Always explicitly specify the expected algorithm.
Token Injection via jku (JWK Set URL)
The jku (JWK Set URL) header claim points to a URL containing the public key. An attacker can set this to their own server and provide their own key. Always whitelist allowed JWK URLs or don't support the jku header.
Cross-Site Scripting (XSS) Token Theft
If a JWT is stored in localStorage, any XSS vulnerability on your site can steal it. This is why HttpOnly cookies are the recommended storage method.
Implementing JWT in Node.js
When to Use (and Not Use) JWT
Good use cases for JWT:
- Single Page Applications (SPAs) communicating with a REST API
- Mobile app authentication
- Microservice architectures where services need to verify tokens independently
- Federated identity (SSO with third-party providers like Google, Auth0)
- API keys with expiration
Consider alternatives when:
- You need immediate token revocation (sessions are better)
- Your tokens need to carry large amounts of data
- You're building a simple server-rendered application (traditional sessions are simpler)
- You need strict control over user sessions (force logout, device management)
Summary
JWT is a powerful tool for stateless authentication, but it requires careful implementation to be secure:
- A JWT has three parts: Header, Payload, and Signature — all base64url-encoded.
- The payload is readable by anyone — never store sensitive data in it.
- Always specify the expected algorithm explicitly when verifying.
- Use short expiration times and implement refresh tokens.
- Store tokens in HttpOnly cookies when possible.
- Always use HTTPS.
- Choose RS256/ES256 for distributed systems, HS256 for monoliths.
JWTs aren't a silver bullet, but understanding how they work — and their limitations — lets you use them effectively and securely in your applications.