How to Decode a JWT Token Online
JWT tokens are everywhere in modern auth flows — but they look like gibberish until you decode them. This guide explains what's inside a JWT, how to read it, and when decoding is useful for debugging.
What is a JWT?
A JSON Web Token (JWT) is a compact, URL-safe string used to represent claims between two parties. In practice, you'll encounter them as authentication tokens: your app logs in, the server returns a JWT, and you send that token in the Authorization header on every subsequent request.
A JWT looks like this:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VyXzEyMyIsIm5hbWUiOiJBbGljZSIsInJvbGUiOiJhZG1pbiIsImlhdCI6MTcwNTMxMjIwMCwiZXhwIjoxNzA1Mzk4NjAwfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5cThree base64url-encoded parts, separated by dots. They are not encrypted — they are signed. Anyone can decode and read the contents. The signature only proves the token hasn't been tampered with.
The three parts of a JWT
Part 1: Header
The first segment contains metadata about the token itself — specifically, which signing algorithm was used.
// Encoded:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
// Decoded:
{
"alg": "HS256",
"typ": "JWT"
}Common values for alg: HS256 (HMAC-SHA256, symmetric),RS256 (RSA-SHA256, asymmetric), ES256 (ECDSA). If you're integrating with an OAuth provider, you'll often see RS256.
Part 2: Payload
The payload contains the actual claims — data the token is asserting. There are registered claim names with well-known meanings, plus custom claims your app defines.
// Encoded:
eyJzdWIiOiJ1c2VyXzEyMyIsIm5hbWUiOiJBbGljZSIsInJvbGUiOiJhZG1pbiIsImlhdCI6MTcwNTMxMjIwMCwiZXhwIjoxNzA1Mzk4NjAwfQ
// Decoded:
{
"sub": "user_123",
"name": "Alice",
"role": "admin",
"iat": 1705312200,
"exp": 1705398600
}Standard registered claims:
sub— subject: the user or entity the token refers toiat— issued at: Unix timestamp when the token was createdexp— expiration: Unix timestamp after which the token is invalidiss— issuer: who created the tokenaud— audience: who the token is intended forjti— JWT ID: a unique identifier for the token (used to prevent replay)
Part 3: Signature
The signature is computed by hashing the encoded header + encoded payload with a secret key (for HS256) or a private key (for RS256/ES256). The server validates the signature on every request to confirm the token is authentic and unmodified.
Decoding a JWT does not verify the signature — that requires the secret or public key. Decoding only unpacks the base64url encoding to reveal the JSON contents.
When to decode a JWT
Debugging authentication errors
Getting a 401 on an authenticated request? Decode the token and check:
- Is
expin the past? The token expired. - Is
audset to the wrong service? The token is for a different API. - Is
subwhat you expect? You might be using a token from the wrong user. - Is the role or permission claim missing? Your auth middleware might not have included it.
Checking expiry
The exp claim is a Unix timestamp (seconds since epoch). To convert it manually:
// exp: 1705398600
new Date(1705398600 * 1000).toISOString()
// → "2024-01-16T10:30:00.000Z"A good JWT decoder shows this as a human-readable date automatically, saving you the conversion.
Inspecting claims from OAuth providers
When integrating Google, Auth0, Okta, or another OAuth provider, the ID token or access token contains claims your app needs (email, name, roles, scopes). Decoding lets you verify the provider is sending exactly what you expect before writing the code to consume it.
Security: never paste production tokens into untrusted tools
This is important. A JWT issued in production is a valid credential. Pasting it into a random online tool means:
- The tool's server might log it
- The payload (including user data) is now on someone else's system
- If the token hasn't expired, it can be replayed
For production tokens, either decode them locally in your browser's DevTools console —atob(token.split('.')[1]) — or use a tool that explicitly processes everything client-side with no server uploads.
Jsonic's JWT decoder runs entirely in your browser. Nothing is sent to any server. That makes it safe to use for inspecting tokens during development and staging — though for sensitive production tokens, local decoding is always the right default.
Decoding a JWT manually
You can decode a JWT in any browser console without a tool:
const token = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VyXzEyMyJ9.signature'
const [header, payload] = token.split('.')
JSON.parse(atob(header)) // → { alg: 'HS256', typ: 'JWT' }
JSON.parse(atob(payload)) // → { sub: 'user_123' }Note: atob expects standard base64, but JWTs use base64url (uses -and _ instead of + and /). For most tokens this doesn't matter, but strictly you should replace those characters first:
function decodeJwtPart(part) {
const base64 = part.replace(/-/g, '+').replace(/_/g, '/')
return JSON.parse(atob(base64))
}Decode a JWT now
Paste any JWT token into Jsonic's JWT Decoder to instantly see the header, payload, and expiry time formatted as human-readable JSON and dates. No server. No uploads.
Open JWT Decoder