
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



