Wernzi Tools Guide
JWT Tokens Explained
JSON Web Tokens carry identity and claims between services in three Base64 parts. Learn their structure, how verification works, and the security rules.
When you log into a modern web app, the server often hands your browser a long string of three Base64 segments separated by dots. That string is a JWT — a JSON Web Token — and it is how the server remembers who you are without storing a session for every user. Your browser sends the token with each request, and the server verifies it on the spot.
JWTs are everywhere in modern APIs, but they are also widely misunderstood — especially the idea that they are encrypted (they are not). This guide explains the three parts of a token, how verification works, and the rules that keep JWTs secure.
The three parts of a JWT
A JWT has three Base64URL-encoded parts separated by dots: header.payload.signature. The header says which algorithm signed the token, usually HS256 (a shared secret) or RS256 (a public/private key pair). The payload carries claims — statements about the user, such as "sub": "12345" (the user ID), "name": "Ada", "iat" (issued at) and "exp" (expires at). The signature is computed over the header and payload using the server's secret key.
Anyone can decode the first two parts — they are just Base64, not encryption. That means you must never put secrets, passwords or sensitive personal data in a payload. Treat a JWT like a postcard: readable by everyone who handles it, but tamper-evident because of the signature.
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9. <- header
{"alg":"HS256","typ":"JWT"}
eyJzdWIiOiIxMjM0NSIsIm5hbWUiOiJBZGEiLCJleHAiOjE3NjMwMDAwMDB9. <- payload
{"sub":"12345","name":"Ada","exp":1763000000}
SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJVadQssw5c <- signatureHow verification works
When a server receives a JWT, it recomputes the signature from the header and payload using its secret key, then compares it with the signature attached to the token. If they match, the token is intact — nobody altered the payload after it was issued. If even one character changed, the signature will not match and the token is rejected. This is what makes JWTs trustworthy without a database lookup.
The server also checks the claims: is the token expired (exp)? Was it issued by a trusted issuer (iss)? Is it meant for this audience (aud)? A token that passes the signature check but fails any of these is still refused. Verification is fast and stateless, which is why JWTs scale so well across many servers.
Common claims you should know
The JWT standard defines a set of registered claims. "iss" names the issuer, "sub" identifies the subject (usually the user), "aud" names the intended audience, "exp" is the expiry time, "nbf" is the earliest time the token is valid, "iat" is when it was issued, and "jti" is a unique token ID useful for revocation lists. Custom claims can carry anything else — roles, permissions, or a display name — but keep the payload small, because the token travels with every request.
Keep expiry times short for access tokens — minutes to an hour is typical — and use a separate refresh token to obtain new ones. Short-lived tokens limit the damage if one is stolen, which leads to the most important security rule of all.
- iss — who issued the token
- sub — who the token is about (usually the user ID)
- exp — when the token expires (Unix timestamp)
- iat — when the token was issued
- aud — who the token is intended for
Security rules that matter
First, always send JWTs over HTTPS. A token sent over plain HTTP can be intercepted, and whoever holds it can impersonate the user until it expires — there is no password check on each request. Second, never store tokens where JavaScript can read them if you can avoid it: localStorage is convenient but vulnerable to cross-site scripting (XSS). HttpOnly cookies are safer because scripts cannot touch them.
Third, never accept the "none" algorithm — a token with alg "none" and no signature must be rejected outright, or an attacker can forge any payload. Fourth, always verify the signature and the expiry on the server; a token that is merely decoded has not been verified at all. Finally, keep secrets secret: with HS256 the same key signs and verifies, so it must never reach the client.
Debugging a JWT
When authentication fails, the token itself usually tells you why. Decode it with a JWT parser and check the pieces: is "exp" in the past? Is "iss" what your server expects? Does the header algorithm match your configuration? Common problems include clock skew between servers (a token that looks expired because the server clock is minutes ahead), a wrong secret after a key rotation, and payloads that grew too large for a header or cookie.
A JWT debugger that shows the decoded header and payload — and verifies the signature when you supply the secret — turns a mysterious 401 error into a five-minute fix.
Access tokens and refresh tokens: how they work together
A common pattern pairs two tokens. The access token is short-lived — minutes to an hour — and is sent with every request; it proves who you are. The refresh token is long-lived — days to weeks — and is stored securely, often in an HttpOnly cookie; it is only sent to one endpoint, whose only job is to issue a fresh access token.
When the access token expires, the client presents the refresh token and gets a new access token without asking you to log in again. If a refresh token is stolen, it can be revoked on the server, which immediately invalidates it — something that is impossible with a stateless access token. This split keeps the damage from a stolen access token small, while still giving users a smooth session that lasts for days.
Try it yourself
Put what you just read into practice with these free tools — no sign-up needed.
Keep learning
- What Is JSON and How to Format It — 6 min read
- How to Generate a Strong Password — 6 min read
- Base64 Encoding Explained — 5 min read