
How to Decode a JWT Token Online for Free
A JSON Web Token (JWT) is a compact, URL-safe string used for authentication and information exchange. When you decode a JWT token, you split it into its three components — header, payload, and signature — and decode each part to inspect the claims, algorithm, and expiration. This is essential for debugging authentication flows, verifying token expiration, and checking which signing algorithm a service uses. A browser-based decoder does this instantly without writing a script or sending your token to a server. This guide covers JWT structure, the decoding process, common claims, algorithm types, and the critical security distinction between decoding and verifying.
JWT Structure: Header.Payload.Signature
A JWT consists of three Base64URL-encoded parts separated by dots:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkFsaWNlIiwiZXhwIjoxNzMyNzU4NDAwfQ.sN3aZqKJ8wQyVbR5xT9mF2pL6hY0jN4kD7sW1cE3bA
Each part serves a specific purpose:
<svg viewBox="0 0 800 260" xmlns="http://www.w3.org/2000/svg" style="width:100%;max-width:800px;margin:24px auto;display:block">
<rect x="0" y="0" width="800" height="260" fill="#f8fafc" rx="12"/>
<text x="400" y="35" fill="#1e293b" font-size="17" font-family="sans-serif" text-anchor="middle" font-weight="bold">JWT Token Structure</text>
<rect x="30" y="60" width="240" height="120" fill="#3b82f6" rx="8"/>
<text x="150" y="90" fill="white" font-size="14" font-family="sans-serif" text-anchor="middle" font-weight="bold">Header</text>
<text x="150" y="115" fill="#dbeafe" font-size="11" font-family="sans-serif" text-anchor="middle">Algorithm & token type</text>
<text x="150" y="140" fill="#dbeafe" font-size="10" font-family="monospace" text-anchor="middle">{"alg":"HS256","typ":"JWT"}</text>
<text x="150" y="165" fill="#dbeafe" font-size="11" font-family="sans-serif" text-anchor="middle">Base64URL encoded</text>
<text x="280" y="120" fill="#94a3b8" font-size="24" font-family="sans-serif" text-anchor="middle" font-weight="bold">.</text>
<rect x="295" y="60" width="240" height="120" fill="#8b5cf6" rx="8"/>
<text x="415" y="90" fill="white" font-size="14" font-family="sans-serif" text-anchor="middle" font-weight="bold">Payload</text>
<text x="415" y="115" fill="#ede9fe" font-size="11" font-family="sans-serif" text-anchor="middle">Claims (user data)</text>
<text x="415" y="140" fill="#ede9fe" font-size="10" font-family="monospace" text-anchor="middle">{"sub":"123","name":"Alice"}</text>
<text x="415" y="165" fill="#ede9fe" font-size="11" font-family="sans-serif" text-anchor="middle">Base64URL encoded</text>
<text x="545" y="120" fill="#94a3b8" font-size="24" font-family="sans-serif" text-anchor="middle" font-weight="bold">.</text>
<rect x="560" y="60" width="210" height="120" fill="#f59e0b" rx="8"/>
<text x="665" y="90" fill="white" font-size="14" font-family="sans-serif" text-anchor="middle" font-weight="bold">Signature</text>
<text x="665" y="115" fill="#fef3c7" font-size="11" font-family="sans-serif" text-anchor="middle">HMAC or RSA signature</text>
<text x="665" y="140" fill="#fef3c7" font-size="10" font-family="monospace" text-anchor="middle">HMAC-SHA256(...)</text>
<text x="665" y="165" fill="#fef3c7" font-size="11" font-family="sans-serif" text-anchor="middle">Not decoded — verified</text>
<text x="150" y="220" fill="#64748b" font-size="11" font-family="sans-serif" text-anchor="middle">Decoded to view</text>
<text x="415" y="220" fill="#64748b" font-size="11" font-family="sans-serif" text-anchor="middle">Decoded to view</text>
<text x="665" y="220" fill="#64748b" font-size="11" font-family="sans-serif" text-anchor="middle">Verified with secret/key</text>
</svg>
The JWT decoder splits the token at the dots, Base64URL-decodes the header and payload, and displays them as formatted JSON. The signature is not decoded — it's a cryptographic value that you verify, not read.
How to Decode a JWT Token
Decoding a JWT is straightforward because the header and payload are Base64URL-encoded, not encrypted. Anyone with the token can read them.
Step 1: Split the Token
Split the JWT at the dot separators to get three strings:
const token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkFsaWNlIiwiZXhwIjoxNzMyNzU4NDAwfQ.signature";
const [headerB64, payloadB64, signatureB64] = token.split(".");
Step 2: Base64URL-Decode Each Part
JWT uses Base64URL encoding, which replaces + with - and / with _, and omits padding. You need to reverse this before decoding:
function base64UrlDecode(str) {
let base64 = str.replace(/-/g, '+').replace(/_/g, '/');
while (base64.length % 4) base64 += '=';
return atob(base64);
}
const header = JSON.parse(base64UrlDecode(headerB64));
const payload = JSON.parse(base64UrlDecode(payloadB64));
console.log(header); // { alg: "HS256", typ: "JWT" }
console.log(payload); // { sub: "1234567890", name: "Alice", exp: 1732758400 }
You can also use the Base64 converter to decode individual parts manually if you're inspecting a token outside of code.
Common JWT Claims
The payload contains claims — statements about the token and the user. Standard claims are defined in RFC 7519:
| Claim | Name | Description |
|---|---|---|
iss |
Issuer | Who issued the token |
sub |
Subject | Who the token is about (usually user ID) |
aud |
Audience | Intended recipient of the token |
exp |
Expiration | When the token expires (Unix timestamp) |
nbf |
Not Before | When the token becomes valid |
iat |
Issued At | When the token was created |
jti |
JWT ID | Unique identifier for the token |
Custom claims are anything the issuer adds — name, email, role, permissions. These vary by application.
Checking Expiration
The exp claim is a Unix timestamp. A good decoder converts it to a human-readable date and tells you whether the token is currently valid or expired. This is the most common debugging task — "why is my API returning 401?" is often an expired token.
Algorithm Types
The alg field in the header specifies how the signature was generated:
| Algorithm | Type | Key | Use Case |
|---|---|---|---|
| HS256 | HMAC + SHA-256 | Shared secret | Simple setups, single server |
| RS256 | RSA + SHA-256 | Public/private key pair | Distributed systems, microservices |
| ES256 | ECDSA + SHA-256 | Elliptic curve key pair | Performance-sensitive systems |
HMAC algorithms use a shared secret. RSA and ECDSA use asymmetric keys — the issuer signs with a private key, verifiers check with a public key. Asymmetric algorithms are preferred when multiple services need to verify tokens without sharing the signing key.
Decoding vs. Verifying: A Critical Distinction
Decoding a JWT only reads the contents — it does not verify authenticity. Anyone can create a JWT with any claims they want. To confirm a token was issued by the expected party and hasn't been modified, you must verify the signature using the secret (for HMAC) or public key (for RSA/ECDSA).
The JWT decoder shows the decoded contents and lets you verify the signature if you provide the secret or public key. For a deeper dive into how JWT authentication works end-to-end, see our jwt decoder online guide.
Security Notes
- JWTs are not encrypted — the header and payload are readable by anyone with the token. Never put passwords, API keys, or sensitive data in claims.
- Always verify signatures in production — decoding is for debugging; your backend must verify signatures before trusting any claim.
- Watch for
alg: none— some older implementations accepted tokens with no signature. Modern libraries reject this, but it's worth checking.
Related Tools
- JWT Decoder — Decode and inspect JWT tokens
- Base64 Converter — Decode Base64URL manually
- JWT Decoder Online Guide — Detailed decoder walkthrough
Published: August 20, 2026
Category: Data Tools
Reading Time: 5 minutes



