You've probably used JSON Web Tokens (JWTs). Maybe you've even implemented a library that handles them. But do you really understand what's going on under the hood? Many developers use JWTs as a black box for authentication, which can lead to dangerous security holes.
This guide is for developers who want to move beyond the surface. We'll break down how JWTs actually work, why they're powerful, and—most importantly—how to use them without exposing your application to common attacks.
The Anatomy of a Token: Header, Payload, Signature
A JWT isn't a single cryptic string; it's three distinct parts, encoded in Base64Url and separated by dots: xxxxx.yyyyy.zzzzz
.
1. The Header (Metadata)
The header is a simple JSON object that provides metadata about the token itself. It typically contains two fields:
"typ"
: The type of token, which is always"JWT"
."alg"
: The signing algorithm used for the signature, such asHS256
(HMAC with SHA-256) orRS256
(RSA).

- This JSON is then Base64Url encoded to form the first part of the JWT.
2. The Payload (The Claims)
This is where the user data lives. The payload contains "claims," which are statements about an entity (typically the user) and additional data. Crucially, the payload is only Base64Url encoded, not encrypted. Anyone who intercepts the token can read its contents. Never store sensitive information in the payload.
Claims come in three types:
- Registered Claims: Recommended, predefined claims like
iss
(issuer),exp
(expiration time), andsub
(subject). These are not mandatory but are highly encouraged. - Public Claims: Custom claims that should have universally unique names (like a URI) to avoid collisions with other applications.
- Private Claims: Custom claims created to share information between two parties that have agreed on their meaning.

- This payload is also Base64Url encoded to form the second part of the JWT.
3. The Signature (The Verification)
The signature is the security gatekeeper. It verifies that the token hasn't been tampered with. It's created by taking the encoded header, the encoded payload, a secret key, and signing them with the algorithm specified in the header.

Only someone with the secret_key
can generate a valid signature for a given header and payload. This is how your server confirms the token is authentic.
How JWT Authentication Works in Practice
The flow is stateless and straightforward, making it perfect for modern web and mobile apps.
- Login: The user sends their credentials (e.g., email and password) to your server.
- Verification & Token Generation: The server validates the credentials. If they are correct, it creates a JWT containing user claims (like user ID and roles) and signs it with a secret key.
- Token Sent to Client: The server sends the newly created JWT back to the client.
- Client Stores Token: The client stores the JWT (typically in memory,
localStorage
, or anHttpOnly
cookie). - Authenticated Requests: For every subsequent request to a protected API endpoint, the client sends the JWT in the
Authorization
header.

- Server Validates Token: On receiving a request, the server inspects the JWT. It recalculates the signature using the header, payload, and its secret key. If the calculated signature matches the signature on the token, the request is trusted, and the server can use the payload data to fulfill the request.
🚨 The JWT Security Checklist You Can't Ignore
JWTs are powerful, but their security depends entirely on proper implementation. Here are the most common pitfalls and how to avoid them.
- Assume Payloads are Public: Remember, the payload is encoded, not encrypted. Anyone can read it. Never put database passwords, API keys, or other sensitive information in a JWT payload.
- Use HTTPS Everywhere: Without HTTPS, an attacker can perform a Man-in-the-Middle (MITM) attack, intercept the token in transit, and gain full access to the user's account.
- Never Trust the
alg
Header: A known attack involves an attacker modifying the header to{"alg": "none"}
and submitting the token. Some poorly configured libraries will see "none" and accept the token without verifying the signature. Always have your backend explicitly check for an expected algorithm (e.g.,HS256
) and reject any others. - Plan for Token Revocation: Because JWTs are stateless, they are valid until they expire. If a token is stolen, the attacker can use it until the
exp
time is reached. To mitigate this, you can implement a server-side blocklist for compromised tokens, though this partially sacrifices the benefit of statelessness. - Use
HttpOnly
Cookies for Storage: If you store JWTs inlocalStorage
, they are vulnerable to being stolen by Cross-Site Scripting (XSS) attacks. Storing the JWT in anHttpOnly
cookie prevents JavaScript from accessing it, providing a strong layer of defense. - Protect Against CSRF: If you use cookies to store JWTs, you must protect against Cross-Site Request Forgery (CSRF). The most effective defense is to set the
SameSite=Strict
orSameSite=Lax
attribute on your cookie.
Conclusion
JWT is a fantastic standard for building fast, stateless authentication systems. It's lightweight, language-agnostic, and widely adopted. However, its simplicity can be deceptive.
True security comes from understanding that a JWT's integrity relies on its verifiable signature, not the secrecy of its payload. By following the security checklist above, you can leverage the power of JWTs while keeping your users and your application safe.