🪙 JWT Decoder

Last updated: June 7, 2026

JWT Decoder

Paste any JSON Web Token below — decodes header & payload locally, nothing is sent anywhere.

Inside the Token: How JWT Decoding Reveals What Your Auth System Is Actually Sending

A backend engineer at a mid-size fintech company spent three days chasing what looked like a session management bug. Users were being logged out mid-transaction, seemingly at random. The logs showed valid login events, no server errors, and the database sessions looked fine. It wasn't until someone thought to actually decode the JWT tokens flying across the wire that the culprit appeared instantly: the exp claim was set to 900 seconds — 15 minutes — while the product team believed sessions lasted 4 hours. A config line changed in a deploy two weeks earlier had gone unnoticed. The entire investigation collapsed into a two-minute fix once someone decoded the token.

That story repeats itself in different forms across every engineering team that uses JSON Web Tokens. The tokens are opaque-looking strings — three chunks of Base64URL separated by dots — and developers routinely treat them as black boxes, trusting that what was put in is what comes out. Decoding them manually should be a first instinct, not a last resort.

What a JWT Actually Contains

A JSON Web Token is not encrypted by default. It is signed. The distinction matters enormously. When a server issues a JWT, it encodes a JSON header and a JSON payload using Base64URL encoding, concatenates them with a dot, then computes a signature over that string using a secret or private key. The resulting structure — header.payload.signature — can be decoded by anyone who possesses the string. The signature only proves the token hasn't been tampered with; it says nothing about confidentiality.

This means that decoding a JWT requires no secret, no server call, and no special permission. The header and payload are plain Base64URL — a URL-safe variant of Base64 that replaces + with - and / with _, and omits padding characters. Any browser, any command line, any decoder can read them. The only thing that requires the secret is verifying the signature, which is a separate operation entirely.

The header typically contains two fields: alg (the signing algorithm, like HS256 or RS256) and typ (almost always "JWT"). The payload is where the real content lives. The JWT specification defines a set of "registered" claims — standardized field names with specific semantics — and allows applications to add any custom claims they need.

The Registered Claims and Why They Trip People Up

The registered claims are where most debugging sessions live. Understanding each one prevents the class of bugs that the fintech engineer experienced.

iat (Issued At) is a Unix timestamp recording when the token was minted. It is not an expiry. A token issued three years ago with no exp claim is technically still valid from a claims perspective — the application logic must decide whether to accept it.

exp (Expiry) is the claim that matters most for session management. It is a Unix timestamp, and a conforming JWT library will reject the token if the current time is past this value. The common mistake is setting this in the wrong unit — seconds versus milliseconds. A token with exp: 1716242622 expires at a specific UTC moment. A token accidentally set to exp: 1716242622000 (milliseconds) will appear to be valid until the year 56,000, and most libraries will either overflow silently or accept it indefinitely.

nbf (Not Before) is the mirror of exp. A token should not be accepted before this timestamp. This claim is less commonly used but appears in scenarios like pre-issuing tokens for scheduled operations — issuing a token today that becomes valid tomorrow morning.

iss (Issuer) identifies who created the token. In multi-service architectures, this is critical: a token issued by the auth service should not be accepted by the payments service unless the issuer matches what the payments service expects. Skipping issuer validation is a common misconfiguration.

aud (Audience) specifies the intended recipient. A token meant for api.example.com should not be accepted by admin.example.com. Libraries often make audience validation opt-in, meaning it is silently skipped unless explicitly configured.

sub (Subject) identifies the principal — usually a user ID. jti (JWT ID) is a unique identifier for the token itself, used in token revocation schemes where the server maintains a blocklist.

Reading Custom Claims in Practice

Beyond the registered claims, real-world JWTs carry application-specific data. A SaaS platform might include plan, org_id, permissions, and feature_flags directly in the payload. An OAuth token from Google includes email, picture, and email_verified. A Kubernetes service account token includes kubernetes.io/serviceaccount/namespace.

Decoding these tokens during development and debugging is how you confirm that the authorization server is actually encoding what you think it's encoding. A permissions array that shows ["read"] when you expected ["read","write"] explains why the API keeps returning 403. A plan: "free" claim on a user who upgraded yesterday points to a caching bug in the token issuance path.

Security Implications of Inspection

Because JWTs are not encrypted, sensitive data should never live in the payload. Full names, email addresses, and role names are commonly included and are fine — they are semi-public by nature and the signature prevents tampering. But social security numbers, payment card data, internal system paths, or anything that would cause harm if intercepted has no place in a JWT payload.

A decoder tool that runs entirely in the browser addresses one specific concern: not wanting to paste tokens into an external service that might log them. A JWT for a production system carries real session context. Sending it to an online service means that service's servers see your token. Client-side decoding removes that risk entirely — the JavaScript does the Base64URL parsing in your browser's memory, and no bytes leave the machine.

The signature itself is not verifiable without the secret or public key, and that limitation is intentional in a client-side tool. For inspection and debugging purposes, the signature's raw value is all you need to see — it confirms the token is structurally complete. Actual signature verification belongs in your backend, where the secret lives.

Algorithm Confusion: The Attack That Starts at the Header

One notorious JWT vulnerability class — the "algorithm confusion" attack — begins in the header. A token signed with RS256 (asymmetric, using a private key) can sometimes be forged if the verifying library accepts HS256 (symmetric, using a shared secret). An attacker changes the alg header from RS256 to HS256, signs the token with the server's public key as the HMAC secret, and if the library blindly trusts the header's algorithm declaration, verification passes.

Reading the alg claim during debugging is therefore not just informational — it is a security audit step. If a token claims HS256 but your system issues RS256, something is wrong. Mature JWT libraries now reject algorithm downgrade attempts by default, but older codebases and custom implementations may not.

Similarly, the alg: "none" attack — where an attacker strips the signature and declares no algorithm — has burned several high-profile deployments. Spotting "none" in the decoded header of a token your system received is a critical red flag.

Making Decoding a Routine Habit

The engineers who debug JWT issues fastest are the ones who decode first and theorize second. When a user reports they were logged out, decode the token from their request log. When an API returns unexpected permissions, decode the token in the Authorization header. When a new auth provider integration behaves strangely, decode the tokens it issues before touching any code.

The information is all there, readable without any server access, any database query, or any special tooling — just Base64URL decoding and JSON parsing. The three-part structure of a JWT is deliberately human-inspectable. Using that property actively, rather than treating the token as opaque infrastructure, is what separates confident JWT debugging from hours of guesswork.

FAQ

Is it safe to paste a production JWT into a decoder tool?
It depends on the tool. A client-side decoder — like this one — runs entirely in your browser without sending data anywhere, so pasting a production token is safe. Avoid pasting tokens into server-side online tools or services you don't control, as they may log the token. Since JWTs carry live session credentials, treat them like passwords when choosing where to decode them.
Can this tool verify the JWT signature?
No, and that is by design. Signature verification requires the secret key (for HMAC algorithms like HS256) or the public key (for RSA/ECDSA algorithms like RS256/ES256). A client-side tool never has access to these keys. Verification must happen on your backend using a trusted JWT library. This tool shows you the raw signature bytes and the signing algorithm so you can confirm what to look for — but cryptographic verification stays server-side.
What does it mean when the exp claim shows EXPIRED?
The exp claim is a Unix timestamp (seconds since January 1, 1970 UTC). When the current time is past that timestamp, the token is expired and a conforming server should reject it. A 401 Unauthorized response from an API often traces back to an expired token. Re-authenticate to get a fresh token with a new expiry. If tokens expire too quickly for your use case, the issue is the session duration configured on the authorization server.
Why does my JWT have three parts but one is just a dot followed by nothing?
A token with no signature — sometimes called an 'unsecured JWT' — has an empty third segment and declares alg: "none" in the header. While technically part of the JWT specification, accepting such tokens is a critical security vulnerability. Any backend that processes a token with alg: "none" should reject it outright. If you see this in a decoder, it means the token was issued without signing and should never be trusted.
What is the difference between HS256 and RS256 in the header?
HS256 is HMAC-SHA256 — a symmetric algorithm where the same secret key is used both to sign and to verify the token. RS256 is RSA-SHA256 — an asymmetric algorithm where a private key signs the token and a public key verifies it. HS256 is simpler but requires every service that verifies tokens to share the secret. RS256 lets you publish the public key openly while keeping the signing key private, which is preferred in microservice architectures and federated identity systems.
Can I decode a JWE (JSON Web Encryption) token with this tool?
No. A JWE is an encrypted token and looks entirely different from a standard JWT — it has five parts instead of three, and the payload is ciphertext, not Base64URL-encoded JSON. Decoding a JWE requires the private key or shared encryption key to unwrap the content encryption key and then decrypt the payload. Standard JWTs (which are signed but not encrypted) are what this tool decodes.