How JWT Authentication Works: A Plain-English Guide
Last updated: July 19, 2026
JSON Web Tokens, or JWTs, show up in almost every modern web application. They power login sessions, protect API endpoints, and carry user identity across services. Yet many developers copy a library snippet, get it working, and move on without understanding what is actually happening inside that long dot-separated string. That gap in understanding leads to real security mistakes. This guide fixes that.
Last updated: July 2026
What a JWT Actually Is
A JWT is a compact, URL-safe string that encodes a set of claims. "Claims" is just a fancy word for key-value pairs: who the user is, what permissions they have, when the token expires. The token looks like this:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTYiLCJuYW1lIjoiQWxpY2UiLCJpYXQiOjE3MjAwMDAwMDB9.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
There are three parts separated by periods. Each part is Base64URL-encoded. The three parts are the header, the payload, and the signature. You can decode any JWT immediately using the JWT Decoder on EveryFreeTool to see the raw JSON inside each section.
Breaking Down the Three Parts
1. Header
The header is a small JSON object that declares the token type and the signing algorithm. A typical header looks like this:
- alg: the algorithm used to sign the token, for example
HS256(HMAC-SHA256) orRS256(RSA-SHA256). - typ: almost always
JWT.
The algorithm choice matters significantly for security, which we will cover below.
2. Payload
The payload holds the claims. There are three types of claims defined by the JWT specification:
- Registered claims: standardized fields like
sub(subject or user ID),iss(issuer),exp(expiration time),iat(issued-at time), andaud(audience). - Public claims: custom fields you define yourself, such as
roleoremail. - Private claims: fields agreed upon between the two parties exchanging the token.
The payload is only encoded, not encrypted. Anyone who holds the token can decode it and read the claims without knowing the secret key. Never put passwords, credit card numbers, or other sensitive data in a JWT payload. Use the JSON Formatter to inspect the decoded payload structure cleanly if you are working with complex nested claims.
3. Signature
The signature is what gives JWTs their security value. The server takes the Base64URL-encoded header, adds a period, adds the Base64URL-encoded payload, and then signs the whole thing using the algorithm and key specified in the header. For HMAC-SHA256, the formula is:
HMAC-SHA256(
base64UrlEncode(header) + "." + base64UrlEncode(payload),
secret
)
When your server receives a token from a client, it re-computes this signature and compares it to the one in the token. If they match, the payload has not been tampered with. If someone modified a single character in the payload, the signature check fails and the token is rejected.
The Full Authentication Flow
- User logs in. The client sends credentials (username and password) to the authentication endpoint.
- Server verifies credentials and, if valid, generates a JWT signed with its secret key. It returns the token to the client.
- Client stores the token. Common storage locations are
localStorage,sessionStorage, or anHttpOnlycookie. Each has different security implications (more on this shortly). - Client sends the token with every subsequent request, typically in the
Authorizationheader as a Bearer token:Authorization: Bearer <token>. - Server verifies the token on each request. It checks the signature, confirms the token has not expired, and optionally checks the
audandissclaims. If verification passes, the server trusts the claims in the payload and processes the request.
You can simulate steps 4 and 5 by sending a real Bearer token to a protected endpoint using the API Request Tester, which lets you set custom headers without writing any code.
HS256 vs RS256: Symmetric vs Asymmetric Signing
HS256 (HMAC-SHA256) uses a single shared secret. Both the service that issues the token and the service that verifies it must know the same secret. This is simple but creates a problem: if multiple services need to verify tokens, they all need access to the secret, increasing exposure.
RS256 (RSA-SHA256) uses a private-public key pair. The issuer signs with the private key. Any service can verify with the public key without knowing the private key. This is the right choice for microservices and systems where a central identity provider issues tokens that many downstream services consume. The public key can be distributed openly without risk.
Other common algorithms include ES256 (ECDSA, shorter signatures, similar security model to RS256) and PS256 (RSA-PSS, a stronger padding scheme than plain RS256). Avoid the none algorithm entirely. Some older libraries accept an unsigned token if alg is set to none, which completely removes security.
Expiration and Refresh Tokens
JWTs are stateless by default. The server does not store them anywhere. This means you cannot "log out" a token the way you invalidate a session. Once a token is valid, it stays valid until it expires or the secret changes.
The standard approach is to issue short-lived access tokens (15 minutes to 1 hour) paired with longer-lived refresh tokens (7 to 30 days). When the access token expires, the client sends the refresh token to a dedicated endpoint to receive a new access token. Refresh tokens should be stored in HttpOnly cookies so JavaScript cannot read them, reducing XSS risk.
If you need true revocation, for example to force-logout a compromised account, you must maintain a token denylist (usually a Redis set of revoked token IDs checked on each request). This adds state back to the system but is sometimes necessary.
Where to Store JWTs on the Client
- localStorage: easy to access from JavaScript, but vulnerable to XSS attacks. Any injected script can read and exfiltrate the token.
- sessionStorage: same XSS risk as localStorage, but the token is cleared when the tab closes.
- HttpOnly cookie: JavaScript cannot read the cookie at all, eliminating the XSS theft vector. You must then protect against CSRF using the
SameSitecookie attribute or CSRF tokens. This is the most secure option for most applications.
Common JWT Security Mistakes
- Not validating the
expclaim. Some libraries do not check expiration unless explicitly told to. Always verify theexpclaim server-side. - Not validating the
algclaim. Specify the expected algorithm explicitly when verifying. Never let the token header dictate which algorithm to use. - Putting sensitive data in the payload. The payload is readable by anyone with the token. Treat it as public information.
- Using a weak secret for HS256. Secrets should be at least 256 bits of entropy. A short, guessable secret can be brute-forced offline once an attacker has a valid token.
- Never rotating keys. Establish a key rotation process. If your signing secret is ever compromised, you need a way to invalidate all existing tokens by rotating the key.
When JWTs Are the Right Choice
JWTs work well for stateless APIs where horizontal scaling matters, for single sign-on across multiple services, and for short-lived authorization grants. They are less ideal when you need instant revocation, when the token payload grows large (every request carries the full payload), or when you are building a simple monolithic app where a server-side session is simpler and equally secure.
Understanding the mechanics, not just the library calls, is what separates a developer who copies a JWT snippet from one who can debug a failing signature, design a secure refresh flow, or choose the right signing algorithm for a given architecture.
Frequently Asked Questions
Can anyone read the data inside a JWT?
Yes. The header and payload in a JWT are Base64URL-encoded, not encrypted. Anyone who has the token can decode those two parts and read the claims inside. This is by design: JWTs are meant to be verified, not kept secret. Never store sensitive information like passwords or financial data in a JWT payload.
What happens if a JWT is stolen?
If an attacker obtains a valid JWT, they can use it to impersonate the user until the token expires. This is why short expiration times matter. You can also maintain a server-side denylist of revoked token IDs to invalidate specific tokens before they expire. Storing tokens in HttpOnly cookies greatly reduces the theft risk by preventing JavaScript from accessing them.
What is the difference between a JWT and a session cookie?
A traditional session stores user state on the server and gives the client an opaque session ID. The server must look up that ID in a database or cache on every request. A JWT stores the state inside the token itself, so the server needs no database lookup to verify it. JWTs trade revocation flexibility for stateless scalability.
Why does my JWT verification fail even when the token looks correct?
The most common causes are a mismatched secret or key, a clock skew between the issuing server and the verifying server causing the exp or nbf claims to fail, or a mismatch between the algorithm declared in the header and the algorithm your verification library expects. Always specify the expected algorithm explicitly rather than reading it from the token header.
How long should a JWT access token last?
Most production systems use access token lifetimes between 15 minutes and 1 hour. Shorter lifetimes limit the damage if a token is stolen, but they require more frequent refresh operations. Pair short-lived access tokens with longer-lived refresh tokens stored in HttpOnly cookies to balance security and user experience.
Related Tools
JWT Decoder
Paste any JWT and instantly see the decoded header, payload, and signature.
JSON Formatter
Format and validate the JSON inside a JWT payload for easier reading.
Hash Generator
Generate HMAC hashes to understand how JWT signatures are constructed.
API Request Tester
Send authenticated API requests with Bearer tokens to test your JWT integration.