JWT Decoder

Paste a JSON Web Token and see the header, payload, and timestamp claims as readable dates. Decoded entirely in your browser.

Your token never leaves your browser. All decoding happens client-side in JavaScript. Pasting a JWT here is no different from inspecting it in your console — verify it yourself: open DevTools → Network tab, paste a token, and watch. There's no outbound request.

All decoding runs in your browser. No data is sent to any server. This tool decodes only — it does not verify signatures (that requires the secret/public key, which you should keep in your application code).

[ Ad slot — replace with AdSense / Ezoic code ]

Header JWT.0

Payload JWT.1

Signature JWT.2

[ Ad slot — replace with AdSense / Ezoic code ]

What is a JSON Web Token?

A JSON Web Token (JWT) is a compact, URL-safe way to represent claims as a single string. The most common use is authentication: a server issues a JWT after the user logs in, and the client sends it back on every subsequent request as proof of identity. JWTs are popular because they're self-contained — the server can verify and read a token without consulting a database, which scales well for stateless APIs.

The format is defined in RFC 7519. A JWT is three base64url-encoded segments separated by dots: header.payload.signature. The header says how the signature was generated, the payload contains the actual claims, and the signature lets a server verify the token wasn't tampered with.

The three parts

Take this token (the one our sample button generates):

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VyLTEy...

The first segment eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9 is the header. Decoded from base64url, that's the JSON {"alg":"HS256","typ":"JWT"} — meaning the token was signed with HMAC-SHA256 and is of type JWT.

The second segment is the payload — the actual claims about the user, expiration, scope, and so on. Like the header, it's just base64url-encoded JSON.

The third segment is the signature, computed over the header and payload using the secret (HS256) or private key (RS256, ES256). It exists so a server receiving the token can prove it was issued by something with access to the signing key, and that nobody has modified it in transit. Decoding a JWT does not require any key — only verifying it does.

Standard payload claims

The JWT spec defines seven "registered" claims that have a standard meaning. Most JWTs use a subset of these plus their own custom claims.

ClaimNameMeaning
issIssuerWho issued the token (often a URL like https://auth.example.com)
subSubjectWho the token is about — usually a user ID
audAudienceWho the token is for — usually an API identifier
expExpirationUnix timestamp after which the token is no longer valid
nbfNot BeforeUnix timestamp before which the token is not yet valid
iatIssued AtUnix timestamp when the token was created
jtiJWT IDUnique identifier for the token — useful for revocation lists

The decoder above shows iat, exp, nbf, and auth_time as both raw integers and human-readable dates with relative time, because these are the claims you most often need to inspect when debugging.

Algorithm types

The alg field in the header tells the verifier which algorithm was used to produce the signature. The most common are:

AlgorithmTypeKey model
HS256HMAC SHA-256Symmetric — same secret signs and verifies
HS384, HS512HMAC SHA-384/512Symmetric, larger output
RS256RSA SHA-256Asymmetric — private signs, public verifies
RS384, RS512RSA SHA-384/512Asymmetric, larger output
ES256ECDSA P-256 SHA-256Asymmetric, smaller signatures than RSA
ES384, ES512ECDSA P-384/521Asymmetric, varying curves
PS256RSA-PSS SHA-256Asymmetric, modern padding
EdDSAEd25519Asymmetric, fast, recommended for new systems
none(no signature)Insecure — see warning above

Asymmetric algorithms (RS, ES, PS, EdDSA) are preferred for systems where the signer and verifier are different parties — the verifier only needs the public key, which can be safely distributed. Symmetric algorithms (HS) are faster but require both parties to share the same secret.

Decoding is not verifying

The single most important security distinction with JWTs: decoding the contents of a token does not prove anything about its authenticity. Anyone can write any claims they want into a JWT-shaped string and ship it to your server. A server that trusts a JWT based only on its decoded contents — without verifying the signature — has effectively no authentication.

This decoder, like every browser-based JWT decoder, exists for inspection and debugging only. It tells you what's in a token, not whether the token is genuine. For the genuine-or-not question, your server needs to verify the signature using the secret or public key associated with the issuer.

Common bug: a developer copies a token from a real production session into this decoder, sees a valid-looking payload with "sub": "admin", and assumes their auth code is working. But if the code accepting that token doesn't verify the signature, an attacker could send a different token with a forged "sub": "admin" claim and get the same access. The presence of valid-looking claims is necessary but not sufficient.

Common bugs this tool helps catch

Programming language reference

Quick reference for decoding a JWT in 8 common languages, without using a library (the decoding itself is just base64url + JSON):

LanguageDecode header (or payload) of token jwt
Python 3.11+import base64, json; json.loads(base64.urlsafe_b64decode(jwt.split('.')[0] + '=' * (-len(jwt.split('.')[0]) % 4)))
Node.js 16+JSON.parse(Buffer.from(jwt.split('.')[0], 'base64url').toString())
Browser JSJSON.parse(atob(jwt.split('.')[0].replace(/-/g,'+').replace(/_/g,'/')))
Javanew String(Base64.getUrlDecoder().decode(jwt.split("\\.")[0]), StandardCharsets.UTF_8)
Godata, _ := base64.RawURLEncoding.DecodeString(strings.Split(jwt, ".")[0])
Rubyrequire 'base64'; require 'json'; JSON.parse(Base64.urlsafe_decode64(jwt.split('.')[0]))
PHPjson_decode(base64_decode(strtr(explode('.', $jwt)[0], '-_', '+/') . str_repeat('=', 3 - (3 + strlen(explode('.', $jwt)[0])) % 4)))
Rustuse base64::{Engine, engine::general_purpose::URL_SAFE_NO_PAD}; URL_SAFE_NO_PAD.decode(jwt.split('.').next().unwrap())

For verification, always use a maintained library — never roll your own signature check. Common libraries: PyJWT (Python), jsonwebtoken (Node.js), jose4j or nimbus-jose-jwt (Java), github.com/golang-jwt/jwt (Go), ruby-jwt (Ruby), firebase/php-jwt (PHP), jsonwebtoken (Rust).

Related tools

If you're working with JWT timestamps, you might also need:

[ Ad slot — replace with AdSense / Ezoic code ]

Frequently asked questions

Is my JWT sent to a server when I decode it here?

No. The decoder is JavaScript that runs in your browser. Your token is never transmitted, logged, or stored anywhere outside this tab. You can verify this yourself: open your browser's developer tools, switch to the Network tab, paste a token, and watch — there's no outbound request. This matters because JWTs often contain real authentication claims, user identifiers, and sometimes API access tokens that you wouldn't want sent to a third party.

Why don't you verify the JWT signature?

Signature verification requires the secret (for HS256) or the public key (for RS256, ES256, etc.). Pasting a real production secret into a web tool is a security risk we don't want to facilitate, even for a tool that runs locally — the muscle memory of pasting secrets into web forms is itself the problem. For verification, use a JWT library in your application code with the keys safely managed there. This tool is for decoding and inspecting only — which is what most JWT debugging actually needs.

What does alg=none mean and why is it dangerous?

alg=none is a JWT algorithm identifier that indicates the token has no signature. It exists in the spec for use cases where the JWT is already inside an encrypted envelope, but it's been the source of many critical security vulnerabilities: an attacker who can craft an alg=none token can sometimes bypass authentication entirely if a server's JWT library accepts it without checking. As of the late 2010s most reputable libraries refuse alg=none by default, but legacy code and custom verification logic still occasionally accept it. If your application produces alg=none tokens, that's a red flag — investigate immediately.

What's the difference between iat, exp, and nbf?

iat (issued at) is when the token was created. exp (expiration) is when it stops being valid. nbf (not before) is the earliest moment the token becomes valid — usually equal to iat, but sometimes set further in the future for tokens that should activate later. A correctly-configured token has iat ≤ nbf ≤ now ≤ exp. If now is outside the [nbf, exp] window, the token should be rejected by any properly-implemented validator. All three are Unix timestamps in seconds.

Can I decode an expired JWT?

Yes. Decoding a JWT is just base64url-decoding the header and payload — no validation is required to read the contents. The expiration check only matters when a server is deciding whether to accept a token for an operation. This decoder will happily show you the contents of an expired token, with a red warning banner so you don't miss that it's expired.

What if my JWT has more than three parts?

If you have a token with five parts separated by dots, that's actually a JWE (JSON Web Encryption) token, not a JWT (JSON Web Signature). JWE tokens are encrypted, meaning their contents are unreadable without the decryption key. This decoder is for JWS-format JWTs only — three parts: header.payload.signature. For JWE you'd need a tool with access to the appropriate decryption key, which is beyond what a public browser-based decoder can do safely.

Why does the payload show binary or weird characters?

Most JWT payloads are JSON — but the spec doesn't strictly require it. Some implementations use compressed payloads (like CBOR, MessagePack, or zip-deflated JSON) inside JWTs for size reasons. If the payload doesn't decode as valid JSON, the tool will show you the raw decoded bytes so you can see what's there, but it can't pretty-print non-JSON content. For compressed payloads, you'd need to know the compression scheme to decode further.

How do I decode JWTs in my own code?

The decoding is just base64url decoding the first two segments and parsing the result as JSON. The article above has the same one-liner pattern in 8 languages. For verification (which requires the signing key), use a maintained library — don't roll your own signature check.