Skip to content

JWT Decoder

Decode JWT tokens online with our free JWT decoder. Instantly inspect header, payload, signature, expiration, algorithm, and claims. 100% browser-based — your token never leaves your device. No signup, no tracking.

No Tracking Runs in Browser Free
JWT Token
Reviewed for RFC 7519 compliance and privacy guarantees — Go Tools Security Team · Apr 22, 2026

What is a JWT?

A JSON Web Token, or JWT (pronounced 'jot'), is a compact, URL-safe token format for carrying claims between two parties. It is defined in RFC 7519 and is the dominant credential format used by OAuth 2.0 access tokens, OpenID Connect ID tokens, API keys in modern auth providers (Auth0, Okta, Clerk, Supabase, Firebase), and inter-service tokens in microservice architectures.

"JSON Web Token (JWT) is a compact claims representation format intended for space-constrained environments such as HTTP Authorization headers and URI query parameters." — RFC 7519, Section 1

A JWT is three Base64URL-encoded JSON objects joined by dots: header.payload.signature. The header describes how the token is signed (the alg claim — for example, HS256 or RS256 — and the typ claim, usually 'JWT'). The payload carries the claims: registered claims like iss, sub, aud, exp, iat, plus whatever custom claims the issuer needs (role, scope, email, tenant ID). The signature is a cryptographic proof, computed over the header and payload with the issuer's secret or private key, that lets the recipient detect tampering.

Crucially, a JWT is encoded, not encrypted. Anyone with the token can read its payload — decoding is just Base64URL and JSON parsing. The security guarantee comes from the signature: an attacker can read a JWT, but cannot produce a different JWT that passes signature verification without the signing key. That is why JWTs are safe to pass over the network, but unsafe to fill with secrets.

A JWT decoder shows you exactly what a token contains — algorithm, claims, expiration — without touching the signature. It is the fastest way to answer 'is this token expired?', 'what role does this user have?', 'which issuer minted this token?', or 'is this an alg:none token I should reject?'. All decoding in this tool runs locally in your browser, so pasting a live production token is safe.

JWT work often pairs with other developer tools. You may need to decode a Base64URL-wrapped segment when debugging a malformed token, URL-decode an Authorization header after capturing it from a proxy, or convert the exp claim to a human date manually. For a deeper walkthrough of how JWTs are signed, verified, and rotated in production, see our Base64 fundamentals guide — Base64URL is the foundation every JWT is built on.

// Decode a JWT in the browser — header & payload only
function decodeJwt(token) {
  const [h, p, s] = token.split('.');
  const pad = (seg) => seg + '==='.slice((seg.length + 3) % 4);
  const decode = (seg) => JSON.parse(
    atob(pad(seg).replace(/-/g, '+').replace(/_/g, '/'))
  );
  return { header: decode(h), payload: decode(p), signature: s };
}

const { header, payload } = decodeJwt(token);
console.log(header);   // → { alg: 'HS256', typ: 'JWT' }
console.log(payload);  // → { sub: 'user_123', exp: 1999999999, ... }

// Expiration check
const expired = payload.exp * 1000 < Date.now();

Key Features

Decode JWT Instantly

Paste and watch the JWT decode in real time — header, payload, and signature parsed on the fly. No Decode button, no round-trip to a server.

Expiration Detection

Automatically reads the exp claim and shows a red badge when the token is expired, with the exact expiry date in your local time zone.

Algorithm-Agnostic

Decodes every JWS algorithm — HS256/384/512, RS256/384/512, PS256/384/512, ES256/384/512, EdDSA, and alg:none.

100% Local

Decoding runs in your browser via native atob and JSON.parse. Your token is never uploaded — safe for production credentials.

Claim-Aware Display

Highlights the registered RFC 7519 claims (iat, exp, nbf, iss, aud, sub, jti) so you can spot auth issues at a glance.

One-Click Copy

Copy the header JSON, payload JSON, or raw signature to your clipboard with a single click — perfect for bug reports and tests.

Examples

HS256 Token (Valid)

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VyXzEyMyIsIm5hbWUiOiJBbGljZSIsInJvbGUiOiJhZG1pbiIsImlhdCI6MTcxNTAwMDAwMCwiZXhwIjoxOTk5OTk5OTk5fQ.4NhxPjwoZxPNuxG-2C5ugGxaUsUJ0QyskAz7Ymz5Sg0
{
  "alg": "HS256",
  "typ": "JWT"
}

{
  "sub": "user_123",
  "name": "Alice",
  "role": "admin",
  "iat": 1715000000,
  "exp": 1999999999
}

HMAC-SHA256 signed token with a subject, role, and future expiration — the most common JWT setup used for session auth.

RS256 Token (Expired)

eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImtleS0yMDI1LTAxIn0.eyJpc3MiOiJodHRwczovL2F1dGguZXhhbXBsZS5jb20iLCJhdWQiOiJhcGkuZXhhbXBsZS5jb20iLCJzdWIiOiI5MDA4NzE2NSIsImlhdCI6MTYwMDAwMDAwMCwiZXhwIjoxNjAwMDAzNjAwLCJzY29wZSI6InJlYWQ6dXNlciB3cml0ZTpwb3N0In0.signature_placeholder
{
  "alg": "RS256",
  "typ": "JWT",
  "kid": "key-2025-01"
}

{
  "iss": "https://auth.example.com",
  "aud": "api.example.com",
  "sub": "90087165",
  "iat": 1600000000,
  "exp": 1600003600,
  "scope": "read:user write:post"
}

RSA-signed OAuth-style access token — note the kid (key ID) in the header and the exp claim showing the token has already expired.

OIDC ID Token

eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLCJzdWIiOiIxMTA1MDIyNTExNTU4OTkwNzY2Mzk1IiwiYXpwIjoiY2xpZW50LWlkIiwiYXVkIjoiY2xpZW50LWlkIiwiZW1haWwiOiJhbGljZUBleGFtcGxlLmNvbSIsImVtYWlsX3ZlcmlmaWVkIjp0cnVlLCJpYXQiOjE3MTUwMDAwMDAsImV4cCI6MTk5OTk5OTk5OSwibm9uY2UiOiJhYmMxMjMifQ.signature
{
  "alg": "ES256",
  "typ": "JWT"
}

{
  "iss": "https://accounts.google.com",
  "sub": "110502251155899076639",
  "azp": "client-id",
  "aud": "client-id",
  "email": "alice@example.com",
  "email_verified": true,
  "iat": 1715000000,
  "exp": 1999999999,
  "nonce": "abc123"
}

OpenID Connect ID token with ECDSA signature, email claims, and a nonce for replay protection.

Alg: none Token (Unsigned)

eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0.eyJzdWIiOiJkZWJ1Zy11c2VyIiwiaWF0IjoxNzE1MDAwMDAwfQ.
{
  "alg": "none",
  "typ": "JWT"
}

{
  "sub": "debug-user",
  "iat": 1715000000
}

Unsigned token with alg:none. Accepting this in production is a classic JWT vulnerability — always reject alg:none server-side.

How to Use

  1. 1

    Paste Your JWT to Decode

    Paste the full JWT — including the three dot-separated segments — into the input box. The decoder runs instantly in your browser; you do not need to click a button.

  2. 2

    Read the Decoded Header, Payload & Status

    Read the algorithm and token type in the decoded header, the claims in the payload, and the expiration / issued-at chips at the top. An expired token is flagged in red.

  3. 3

    Copy the Decoded Output

    Use the Copy button on each panel to copy the decoded header JSON, payload JSON, or raw signature. Your token was never sent anywhere — decoding happened locally in your browser.

Common Errors

Accepting alg:none

An unsigned JWT can be forged by anyone. Never allow alg:none in production — always pass an explicit algorithm list to your verify call.

✗ Wrong
jwt.verify(token, secret)  // library default may allow 'none'
✓ Correct
jwt.verify(token, secret, { algorithms: ['RS256'] })

Missing exp Claim

A JWT without exp lives forever. If a token is ever leaked, there is no natural revocation point. Always set an expiration appropriate to the token type.

✗ Wrong
{ "sub": "user_123", "role": "admin" }  // no exp
✓ Correct
{ "sub": "user_123", "role": "admin", "exp": 1715003600 }

Storing Secrets in the Payload

JWT payloads are not encrypted — anyone with the token can read them. Never put passwords, API keys, or untruncated PII inside a JWT payload.

✗ Wrong
{ "sub": "user_123", "password": "hunter2" }
✓ Correct
{ "sub": "user_123", "role": "admin" }  // payload stays minimal

Common Use Cases

Decode Authorization Bearer Tokens
Decode JWT tokens from Authorization: Bearer headers to verify the claims, audience, and expiration your backend is receiving.
Decode OAuth 2.0 & OIDC Tokens
Decode access tokens and ID tokens returned from authorization servers (Auth0, Okta, Google, Keycloak) during OAuth 2.0 and OpenID Connect integration.
Expired Session Diagnosis
Confirm in one second whether a rejected token is expired, uses the wrong audience, or has a clock-skew problem.
Key Rotation Checks
Read the kid (key ID) in the header to verify your JWKS rotation is handing out tokens signed with the expected key.
Security Reviews
Spot tokens signed with alg:none, missing exp, or leaking PII in the payload during code review and pentesting.
Microservice Token Inspection
Decode service-to-service tokens inside a mesh to see which scopes and subject a downstream call is authorizing.

Technical Details

RFC 7519 Compliant
Handles JWS tokens conforming to RFC 7519 (JWT), RFC 7515 (JWS), and RFC 7518 (JWA) — all registered algorithms are supported for decoding.
Base64URL Decoding
Uses the URL-safe Base64 alphabet (- and _ instead of + and /) defined in RFC 4648, with padding-tolerant parsing.
Browser-Native, Zero Dependencies
Built on the browser's atob, TextDecoder, and JSON.parse — no external libraries, no network calls, no telemetry.

Best Practices

Never Trust Without Verifying
A decoder shows claims; it does not prove them. Always verify the signature server-side against the issuer's key before trusting any claim.
Reject alg:none in Production
Configure your JWT library with an explicit allowlist of algorithms. Never accept alg:none, and be suspicious of alg mismatches on key rotation.
Keep Payloads Lean
Put identifiers and short-lived claims in the JWT; keep bulky data behind an opaque session ID. Large tokens cost bandwidth on every request.

Frequently Asked Questions

How do I decode a JWT token online?
Paste the full JWT — all three dot-separated segments (header.payload.signature) — into the decoder above. Decoding happens instantly in your browser: the header and payload are Base64URL-decoded to readable JSON, and the signature is displayed as a raw string. A status row surfaces the signing algorithm, issued-at time, and expiration, so you can spot an expired token at a glance. To decode a JWT manually, split the token on dots, Base64URL-decode the first two segments, and parse them as JSON — anyone with the token can read its claims because the payload is encoded, not encrypted. This decoder is safe to use with production tokens because nothing ever leaves your device: no network request, no logging, no tracking.
What is a JWT (JSON Web Token)?
A JSON Web Token (JWT) is a compact, URL-safe credential that carries claims between two parties. Defined in RFC 7519, it consists of three Base64URL-encoded sections joined by dots: the header (algorithm and token type), the payload (claims — data about the user and the token itself), and the signature (a cryptographic proof that the token was issued by a trusted party). JWTs are the standard way to represent access tokens in OAuth 2.0 and ID tokens in OpenID Connect.
Is my token safe with this JWT decoder?
Yes. All decoding runs in your browser using native JavaScript (atob and TextDecoder). Your token is never sent to a server, never logged, never stored, and never used for analytics. There are no cookies and no tracking. This matters because JWTs can contain live access tokens — pasting them into a remote debugger would be equivalent to handing over a credential. Our tool is safe to use with production tokens.
How does a JWT decoder work?
A JWT decoder splits the token by dots into three parts, Base64URL-decodes the header and payload, and parses them as JSON. The signature is left as an opaque Base64URL string because verifying it requires the issuer's secret or public key — something a client-side decoder cannot do safely. This means decoding is instant and reveals the claims, but you must verify the signature server-side with the correct key before trusting anything inside.
Can this tool verify a JWT signature?
No, and it intentionally does not. Signature verification requires the issuer's secret (for HMAC) or public key (for RSA/ECDSA/EdDSA), which should never be pasted into a public web tool. Verification must happen on your server, in your auth middleware, or inside an SDK that has access to your JWKS endpoint. This decoder is for inspecting what a token claims — it does not imply the token is authentic or untampered.
What are iat, exp, nbf, iss, aud, sub, and jti?
These are the registered claims from RFC 7519. iat (issued at) is the Unix timestamp when the token was created. exp (expiration) is when the token stops being valid — this tool converts it to a human-readable date and marks the token as expired if exp is in the past. nbf (not before) is the earliest time the token can be used. iss (issuer) identifies who created the token. aud (audience) names the intended recipient. sub (subject) identifies the principal — usually a user ID. jti is a unique token ID used to prevent replay. Application-specific claims (role, scope, email, name) live alongside these.
My JWT is expired — why does the decoder still decode it?
Decoding is not the same as validating. A JWT decoder reads the content regardless of expiration, so you can inspect an expired or otherwise invalid token to debug why it was rejected. The 'Expired' badge in this tool compares the exp claim against your local clock and flags tokens whose exp is in the past. A real authentication server would reject the token outright — but a decoder that refused to show expired tokens would be useless for debugging.
What is the difference between JWT, JWS, and JWE?
JWT is the general concept — a JSON object encoded as a compact token. JWS (RFC 7515) is a signed JWT: the payload is readable by anyone who decodes it, and a signature proves it was not tampered with. This is by far the most common JWT you will encounter. JWE (RFC 7516) is an encrypted JWT: the payload itself is ciphertext and cannot be decoded without the decryption key. This tool decodes JWS tokens. A JWE token will decode only to its header — the encrypted payload is not readable without the key.
Why is alg:none dangerous?
A JWT with alg:none has no signature — anyone can construct one, claiming to be any user. Early JWT libraries accepted alg:none by default, leading to a well-known class of authentication bypasses where an attacker would strip the signature, set alg to none, and forge an admin token. Every mature JWT library now rejects alg:none unless explicitly allowed, and you should never accept it for authenticated requests. This decoder will still show you an alg:none token, because inspecting one during debugging is legitimate — but treat any such token received in production as hostile.
Which algorithms does this JWT decoder support?
Decoding the header and payload works for every algorithm, because decoding only needs Base64URL and JSON parsing — it is algorithm-agnostic. The tool correctly reads tokens signed with HS256, HS384, HS512 (HMAC), RS256, RS384, RS512 (RSA + SHA), PS256, PS384, PS512 (RSA-PSS), ES256, ES384, ES512 (ECDSA), EdDSA (Ed25519/Ed448), and unsigned tokens (alg:none). Only signature verification is algorithm-specific, and this tool does not perform verification.
Should I store JWTs in localStorage or cookies?
Prefer HttpOnly, Secure, SameSite=Strict cookies for session tokens. A token in localStorage is readable by any JavaScript that runs on the page, so a single XSS vulnerability leaks every active session. HttpOnly cookies are invisible to JavaScript, which shrinks the blast radius of XSS to what an attacker can do within a live page — not a stolen token they can replay for days. If you must use localStorage (for example, for cross-domain apps), keep access token lifetimes short (minutes, not hours) and use a separate refresh token in an HttpOnly cookie.
How do I decode a JWT in Node.js, Python, or Go?
Node.js: jsonwebtoken.decode(token) for read-only, jsonwebtoken.verify(token, key) for verification. Python: PyJWT.decode(token, options={'verify_signature': False}) to read, pass a key to verify. Go: jwt.ParseUnverified(token, claims) for read-only, jwt.Parse(token, keyFunc) for verification. In every language, never verify with options={'verify_signature': False} in production code — that is what this web tool does deliberately for debugging, and it is only safe when you are inspecting, not authenticating.
What is the maximum size of a JWT?
The JWT standard does not impose a hard limit, but headers in most web servers default to around 8 KB. Keep tokens under 4 KB so they fit comfortably in Authorization headers and cookies. If your token is larger than that, you are probably putting too many claims in the payload — move bulky data behind an opaque session ID and fetch it from your backend when needed. Bloated JWTs also get costly on every request because they are sent with every API call.
I pasted my token and got 'Invalid JWT format' — what's wrong?
A valid JWT has exactly three parts separated by dots: header.payload.signature. Common causes: (1) you accidentally copied only the payload segment, (2) whitespace or newlines were pasted in the middle, (3) the token was truncated in transit (common with terminal wrapping), (4) the token is a JWE where the format is header.encryptedKey.iv.ciphertext.tag (five segments), or (5) the token was URL-encoded and you need to URL-decode it first. Check the raw value your API returned — most editors show invisible characters on hover.
Can I decode a JWT without the secret key?
Yes — the header and payload are Base64URL-encoded, not encrypted. Anyone who has the token can read its claims without any key. This is by design: the payload is meant to be readable so the recipient can make authorization decisions from it. The secret or public key is only required to verify that the token has not been tampered with. This is why you must never put sensitive data (passwords, private keys, PII beyond what the recipient already knows) inside a JWT payload.
My JWT works in Postman but my backend rejects it — how do I debug?
Decode the token here and check: (1) exp — is it in the future relative to the server's clock? Server clock skew is a frequent culprit. (2) iss / aud — do they exactly match what your backend expects? A mismatch on aud is the most common false-negative. (3) alg — does your verification code allow that algorithm? An HS256 token will fail against a library configured for RS256 only. (4) kid — if you use key rotation, is the key ID in the header present in your JWKS? (5) signature — have you pasted the right secret/public key? This decoder surfaces (1), (2), (3), and (4) in the header and payload views so you can eliminate them quickly.

Related Tools

View all tools →