Skip to main content

JWT Decoder

Try Free →
Developer Tools

JWT Explained: How JSON Web Tokens Actually Work

Learn what JSON Web Tokens are, how their three parts work, what claims mean, and the security rules every developer must follow when using JWTs for authentication.

8 min read
··Updated: 24 May 2026·By Helperzy Team

JSON Web Tokens, or JWTs, power authentication in countless modern web applications and APIs. If you have logged into a single-page app or called a protected API, you have probably handled one. Yet JWTs are widely misused, and the mistakes can be severe — leaked secrets, tokens that cannot be revoked, sensitive data exposed in plain sight. This guide explains exactly what a JWT is, how its three parts fit together, what claims do, and the security rules that separate safe implementations from vulnerable ones. Understanding these fundamentals protects both you and your users.

The Three Parts of a JWT

A JWT is a single string split into three sections separated by dots, looking like xxxxx.yyyyy.zzzzz. Each section is Base64URL-encoded and serves a distinct purpose. The header is the first part. It describes the token itself — primarily the signing algorithm used, such as HS256 or RS256, and the token type. When decoded, it is a small JSON object like {"alg": "HS256", "typ": "JWT"}. The payload is the second part. It contains the claims — the actual data the token carries, such as the user's ID, their role, and when the token expires. This is the information your application reads to know who is making a request. The signature is the third part. It is created by signing the encoded header and payload with a secret key or private key. The signature is what makes the token trustworthy: it proves the header and payload have not been tampered with. Anyone can read the first two parts, but only the holder of the key can produce a valid signature, which is the entire foundation of JWT security.

Understanding Claims

Claims are the statements stored in the payload. The JWT standard defines a set of registered claims with short, reserved names that tools and libraries understand automatically. Common registered claims include: sub (subject — usually the user ID), iss (issuer — who created the token), aud (audience — who the token is intended for), exp (expiration time as a Unix timestamp), iat (issued at time), and nbf (not before — the token is invalid until this time). The exp claim is especially important because it limits how long a token remains usable. Beyond registered claims, you can add your own custom claims, such as a user's role, permissions, or email. These are useful because the server can read them directly from the token without a database lookup, which is what makes JWTs stateless and fast. The critical caveat is that all claims are visible. Because the payload is only encoded, not encrypted, anyone with the token can read every claim. Include only data that is safe to expose, and keep the payload small, since the token travels with every request.

Decoding Is Not Verifying

This distinction is the most important security concept in working with JWTs, and getting it wrong creates serious vulnerabilities. Decoding a JWT means Base64-decoding the header and payload to read their contents. This requires no secret and no special permission — any tool or person holding the token can decode it in an instant. A JWT decoder shows you what is inside, nothing more. Decoding tells you what a token claims, but gives you no assurance those claims are true. Verifying a JWT is the entirely separate process of recomputing the signature using the secret key (for symmetric algorithms) or the public key (for asymmetric ones) and confirming it matches the signature in the token. Only verification proves the token was genuinely issued by your server and has not been altered. The practical rule is absolute: your backend must always verify the signature before trusting any claim. Never make an authorization decision based on a decoded but unverified token. An attacker can craft a token with any claims they like — only signature verification catches the forgery. Treat decoding as inspection and verification as trust.

Critical Security Rules

Several rules separate secure JWT use from dangerous mistakes. Never store secrets in the payload. Passwords, API keys, and private data must never go in a JWT, because the payload is readable by anyone holding the token. Treat it as public. Protect your signing key fiercely. For symmetric algorithms like HS256, the same secret signs and verifies tokens. If it leaks, an attacker can forge valid tokens for any user. Store it in environment variables or a secrets manager, never in source code. Always set a short expiration. Because JWTs cannot easily be revoked before they expire, a stolen long-lived token is a long-lived problem. Short lifetimes paired with refresh tokens limit the damage. Validate the algorithm. A known attack tricks servers into accepting tokens signed with the 'none' algorithm or downgrades RS256 to HS256. Configure your library to accept only the specific algorithm you expect. Always verify the signature, audience, and expiration on every request. Skipping any of these checks opens a hole an attacker will eventually find.

When JWTs Are the Right Choice

JWTs are not always the best fit, and choosing them thoughtfully matters. They shine for stateless authentication across distributed systems. Because the token carries its own claims, any server with the verification key can validate a request without sharing a session store. This makes JWTs excellent for microservices, APIs consumed by mobile apps, and scenarios where you want to avoid central session lookups on every request. They also work well for short-lived, single-purpose tokens such as email verification links, password reset tokens, and temporary access grants, where a self-contained expiring credential is convenient. They are a weaker choice when you need instant revocation. Since a valid JWT stays valid until it expires, logging a user out everywhere or banning a compromised account immediately requires extra machinery like a token blocklist, which reintroduces the server-side state JWTs were meant to avoid. For traditional web apps where a server-side session store is already available and instant revocation matters, classic sessions are often simpler and safer. Choose JWTs when statelessness genuinely helps, not by default.

Key Takeaway

A JWT is a signed, self-contained token with three parts — header, payload, and signature — that carries claims about a user in a way any holder can read but only the key holder can forge. The two rules that matter most are never trust a token without verifying its signature, and never store secrets in the payload, since it is readable by anyone. Used with short expiration times and careful key management, JWTs offer powerful stateless authentication. Used carelessly, they become a security liability.

Frequently Asked Questions

Does decoding a JWT mean it is verified?

No, and confusing the two is a dangerous mistake. Decoding a JWT just reads its Base64-encoded contents, which anyone can do without any secret. Verification is the separate, critical step of checking the signature with the secret or public key to confirm the token is authentic and unaltered. A decoder tool shows you the contents but never proves the token is valid. Your server must always verify the signature before trusting any claim inside a JWT.

Is it safe to store sensitive data in a JWT?

No. The payload of a standard JWT is only Base64-encoded, not encrypted, so anyone holding the token can read every claim inside it instantly. Never put passwords, secret keys, or private personal data in a JWT payload. Treat the payload as fully public information. If you genuinely need to carry confidential data in a token, use an encrypted variant (JWE) rather than a standard signed JWT, and even then minimize what you include.

What is the difference between a JWT and a session?

A traditional session stores state on the server and gives the client only an opaque session ID; the server looks up the session data on each request. A JWT is stateless — it carries the user's claims inside the token itself, so the server can validate it without a database lookup. JWTs scale well across servers but are harder to revoke before expiry. Sessions are easy to revoke instantly but require shared server-side storage.

How should I store JWTs on the client?

Storage choice involves real trade-offs. Storing a JWT in localStorage is simple but exposes it to theft through cross-site scripting (XSS) attacks, since any injected script can read it. Storing it in an HttpOnly cookie protects against XSS because JavaScript cannot read the cookie, but introduces cross-site request forgery (CSRF) risk that you must mitigate. Many teams use HttpOnly cookies with CSRF protection and keep access tokens short-lived to limit the damage of any leak.

Why do JWTs expire and what is a refresh token?

JWTs include an expiration claim because they are hard to revoke once issued — a stolen token stays valid until it expires. Keeping the lifetime short, often minutes, limits the window an attacker can use a stolen token. A refresh token is a separate, longer-lived credential stored securely that lets the client obtain a new short-lived access token without forcing the user to log in again, balancing security with a smooth experience.