JWT Tokens Demystified: What Every Developer Must Know About Authentication
You've probably copied a JWT token from an Authorization header, stared at that wall of letters and dots, and wondered what's actually in there. The good news? A JWT isn't encrypted — it's just encoded. You can read every claim inside it if you know how to look.
The Three-Part Structure You Need to Understand
Every JWT looks like three random strings glued together with dots. That's not random — it's a deliberate structure. The first part is the header, the second is the payload, and the third is the signature.
Each part is Base64Url encoded — not encrypted. Base64Url is just an encoding scheme for safely transmitting binary data as text. Anyone with the token can decode the header and payload. The signature is what prevents tampering, not obscurity.
Decode that header and you get {"alg":"HS256","typ":"JWT"}. Decode the payload and you get your user data. Simple as that.
What Lives Inside the Payload — and What Shouldn't
The payload contains claims — statements about the user and additional metadata. There are three categories of claims you'll encounter:
Registered claims are standardized and understood by all JWT libraries. The important ones are sub (subject/user ID), iat (issued at), exp (expiration), iss (issuer), and aud (audience).
Public claims are custom claims that your application defines. Things like role, email, name, or permissions. These are application-specific.
Private claims are agreed upon between specific parties sharing a token — not registered or public.
⚠️ Critical: Never store passwords, payment card numbers, Aadhaar numbers, or any sensitive personal data in the JWT payload. It's encoded, not encrypted. Any person with the token string can read everything in the payload.
Real Developer Scenarios Where JWT Decoding Saves Time
🇮🇳 Rohit — Pune, India (Backend Developer)
Rohit's Spring Boot API is returning 401 Unauthorized errors intermittently. He decodes the JWT from the failing requests and discovers the exp timestamp shows the token expired 5 minutes ago. The frontend wasn't refreshing tokens on time.
🇮🇳 Ananya — Delhi, India (Full Stack Developer)
Ananya is implementing role-based access control. She decodes tokens from staging to verify that her backend is correctly embedding the role: "admin" claim for admin users before writing frontend permission checks.
🇺🇸 Marcus — Austin, USA (Security Engineer)
Marcus audits a fintech app's JWTs. He finds the algorithm claim in the header is set to none — a critical vulnerability that allows unsigned tokens. Decoding and inspecting the header reveals the problem immediately.
JWT vs Session Tokens — When to Choose Which
Sessions store user state on the server. The client gets a session ID, and the server looks up the state in a database or memory store on every request. JWTs store state in the token itself — the server doesn't need to look anything up.
JWTs work well for stateless APIs, microservices, and mobile apps where you want to avoid server-side session storage. They're also great when multiple services need to verify user identity without calling a central auth server on every request.
Sessions are better when you need instant token revocation. Revoking a JWT before it expires is hard — you either need a blocklist (which makes it stateful again) or very short expiration times. Sessions can be invalidated by simply deleting them from the store.
The Security Mistakes That Keep Appearing in JWT Implementations
After reviewing many codebases, the same mistakes keep showing up. Here are the ones worth watching for:
- Algorithm confusion attacks: Using
alg: noneor allowing servers to accept any algorithm from the token header. Always verify the algorithm server-side. - Storing JWTs in localStorage: localStorage is accessible to JavaScript and vulnerable to XSS. HttpOnly cookies are safer for storing auth tokens.
- Overly long expiration: A 30-day JWT with no refresh mechanism is a security risk if the token is stolen. Use short-lived access tokens (15-60 minutes) with refresh tokens.
- Not validating the aud claim: A token issued for service A should not be accepted by service B. Always validate the audience claim.
- Putting sensitive data in the payload: This one bears repeating. The payload is visible to anyone with the token.
Reading the exp and iat Claims Correctly
Both exp (expiration) and iat (issued at) are Unix timestamps — seconds since January 1, 1970. When you see "exp": 1737724800, that's not a date you can read directly.
Convert it: multiply by 1000 to get milliseconds, then pass to new Date() in JavaScript. Our JWT decoder does this automatically and shows you the human-readable date alongside the raw value.
If you're checking token expiry manually: compare the exp value to Math.floor(Date.now() / 1000). If exp is less than the current timestamp, the token has expired. Always check this on the server — never trust client-side expiry checks alone.
JWT in Different Languages and Frameworks
Decode Your JWT Token Instantly
Paste any JWT and see the header, payload, and expiry time in a readable format. Works entirely in your browser.
Use JWT Decoder Tool →Recommended Hosting
Hostinger
If you are building a website for your tools, blog, or store, reliable hosting matters for speed and uptime. Hostinger is a popular option used worldwide.
Visit Hostinger →Disclosure: This is a sponsored link.
