Skip to content

Runs entirely in your browser. Nothing you paste leaves this page.

Free / No sign-up

JWT decoder.

Decode a JSON Web Token's header and payload, read exp, iat and nbf as real dates and see whether it has expired. Free, and nothing leaves your browser.

Decoding is not verification. Anyone can create a token with these claims.

Header

{ }

Payload

{ }

Signature

...

Verify it on your server with the issuer's secret or public key (for example via its JWKS endpoint) before trusting any claim.

Paste a token. It is decoded in this tab and never sent anywhere.

How to use it.

  1. 01

    Paste a token, or a full Bearer header value.

  2. 02

    Read the colour-coded header, payload and signature parts.

  3. 03

    Check the time claims and status, then verify the signature on your server.

What it does.

Everything this tool handles, all of it inside your browser tab.

  • Decodes the header and payload into formatted JSON
  • Colour-codes the header, payload and signature
  • Accepts a raw token or a Bearer header value
  • Shows exp, iat, nbf and auth_time as local dates with a relative hint
  • Labels the token active, expired or not yet valid
  • Recognises encrypted five-part JWE tokens
  • Clear errors for wrong part counts, bad Base64URL and non-JSON parts
  • UTF-8 safe decoding of names and other non-ASCII claims
  • Copy the header or payload JSON in one click
  • Never asks for a secret and never sends the token anywhere

Worked examples.

  • Decode a JWT: header and payload

    eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
    
    Header:  {"alg": "HS256", "typ": "JWT"}
    Payload: {"sub": "1234567890", "name": "John Doe", "iat": 1516239022}
    Issued:  18 Jan 2018, 01:30:22 UTC

    The widely used sample token. It has iat but no exp, so it never expires on its own; the decoder shows the issue time and no status badge.

  • Check if a JWT is expired

    Payload: {"sub": "user_42", "iat": 1767222000, "exp": 1767225600}
    
    Issued   1767222000 -> 31 Dec 2025, 23:00:00 UTC
    Expires  1767225600 -> 1 Jan 2026, 00:00:00 UTC
    Status   expired

    exp is compared with your device clock. Dates are shown in your own time zone; the UTC values are given here for reference.

  • Decode a Bearer token from an Authorization header

    Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VyXzQyIiwiaWF0IjoxNzY3MjIyMDAwLCJleHAiOjE3NjcyMjU2MDB9.<signature>
    
    > The Bearer prefix is removed before decoding.

    Paste the header value as it appears in your browser's Network tab or an API client. Leave out the "Authorization:" name itself.

  • exp in milliseconds instead of seconds

    Payload: {"exp": 1767225600000}
    
    Expires -> the year 57971

    NumericDate is in seconds. A date tens of thousands of years away means the issuer used Date.now() without dividing by 1000, and most verifiers will treat the token as never expiring.

  • An encrypted JWE token

    eyJhbGciOiJSU0EtT0FFUC0yNTYiLCJlbmMiOiJBMjU2R0NNIn0.<key>.<iv>.<ciphertext>.<tag>
    
    > This looks like an encrypted JWE (5 parts). Its contents cannot be read without the decryption key.

    Five dot-separated parts mean encryption. Only the first part, the JWE header, is plain Base64URL: here it names RSA-OAEP-256 key wrapping and A256GCM content encryption.

How to decode a JWT

A JWT (JSON Web Token, RFC 7519) in its usual signed form is three Base64URL strings joined by dots: header.payload.signature. The header is a JSON object that names the signing algorithm (alg) and often the token type (typ) and a key ID (kid). The payload is a JSON object of claims about the subject. The signature is binary data, also Base64URL-encoded.

Decoding is mechanical. Split the token on the dots, convert each of the first two parts from Base64URL (RFC 4648, section 5) to bytes, read the bytes as UTF-8 and parse the JSON. This tool does exactly that in your browser. It accepts a raw token or an Authorization header value starting with Bearer, colour-codes the three parts, pretty-prints the header and payload, and turns the time claims into dates. You can do the same by hand with the Base64 decoder in URL-safe mode.

In application code, avoid hand-rolled decoding for anything security-related. Maintained libraries, such as jose for JavaScript, PyJWT for Python or the JWT support built into your web framework, decode and verify in one call and reject tokens that fail any check.

Decoding is not verification

Anyone can read a JWT, and anyone can create one with any claims they like. What makes a token trustworthy is its signature, checked on the server with the issuer's key. Never authorise a request because a decoded payload says role is admin.

With HS256 the issuer and the verifier share one secret (HMAC with SHA-256). With RS256, ES256 or EdDSA the issuer signs with a private key and anyone can verify with the public key, which identity providers usually publish as a JWKS (JSON Web Key Set) endpoint; the kid header tells you which key to use.

Good verification follows RFC 8725, the JWT best current practice: allow only the algorithms you expect, reject alg: none, never let the token's own header choose between HMAC and public-key verification (the classic algorithm-confusion attack), and check iss, aud and exp as well as the signature. Use a maintained library for your language rather than writing this yourself.

What do exp, iat and nbf mean in a JWT?

RFC 7519 registers seven standard claims: iss (issuer), sub (subject), aud (audience), exp (expiration time), nbf (not before), iat (issued at) and jti (a unique token ID). All are optional, but most APIs require at least exp.

The time claims are NumericDates: whole seconds since 1 January 1970 UTC, not milliseconds. A token is expired once the current time is at or after exp, and not yet valid before nbf. The specification allows a small leeway, usually no more than a few minutes, to absorb clock differences between servers.

This decoder shows exp, iat, nbf and the OpenID Connect auth_time claim as dates in your local time zone with a relative hint such as "in 2 hours", and labels the token active, expired or not yet valid against your device clock. To convert other epoch values, use the Unix timestamp converter.

Common JWT errors and what they mean

"jwt malformed" or a decoding error usually means the value is not a complete token: it was truncated, still wrapped in quotes, URL-encoded, or copied with a line break. This tool reports when a value has the wrong number of parts, when a part contains characters outside the Base64URL alphabet, or when a part decodes but is not a JSON object.

"invalid signature" means the token was changed or is being checked with the wrong key or algorithm. Common causes are mixing up environments, a rotated key that the verifier has not fetched yet, or a secret with stray whitespace.

"jwt expired" means exp has passed. If a freshly issued token is already expired or not yet valid, compare server clocks. If the exp date decodes to tens of thousands of years in the future, the issuer wrote milliseconds instead of seconds. An audience or issuer mismatch means the token was minted for a different API or tenant.

JWT vs session cookies, and where to store tokens

A session cookie holds an opaque ID and the server looks the session up on each request, so revoking access is instant. A JWT carries its claims with it, so any service holding the key can check it without a database lookup. The trade-off is revocation: a stolen JWT stays valid until it expires, which is why access tokens are usually short-lived and paired with refresh tokens.

In browsers, tokens in localStorage can be read by any script that runs on the page, so a cross-site scripting bug exposes them. An HttpOnly, Secure, SameSite cookie keeps the token away from JavaScript. Our guide to sessions, JWTs and passkeys compares the options in depth.

JWS, JWE, ID tokens and access tokens

Most JWTs are JWS tokens: signed but readable. A JWE (RFC 7516) is encrypted and has five parts instead of three, so its payload cannot be read without the decryption key. This decoder recognises the five-part shape and tells you rather than showing garbage.

In OAuth and OpenID Connect, the ID token is always a JWT meant for the client application. Access tokens may be JWTs (RFC 9068 defines a profile for that) or opaque strings, and they are meant for the API. If a provider documents its access tokens as opaque, do not build client code that depends on decoding them, because the format can change.

Questions, answered

Something else on your mind? Ask a consultant and get a reply within one business day.

Is it safe to paste a production token here?

The token is decoded in this tab and never sent anywhere. Still, a valid token is a credential: treat it like a password, and prefer expired or test tokens when debugging.

Can a JWT be decoded without the secret?

Yes. The header and payload are only Base64URL-encoded, not encrypted, so anyone holding the token can read them. The secret or key is needed only to create or verify the signature.

Why doesn't this verify the signature?

Verification needs the issuer's secret or public key and belongs on your server, using a maintained JWT library. A browser tool that asks for your signing secret would be a security risk.

How do I check if a JWT has expired?

Paste it here and look at the status badge and the Expires row. Programmatically, compare the exp claim (seconds since 1970) with the current Unix time in seconds, allowing a small leeway for clock skew.

What is the difference between HS256 and RS256?

HS256 uses one shared secret to both sign and verify, so every verifier could also mint tokens. RS256 signs with a private key and verifies with a public key, so APIs can check tokens without being able to create them.

What does alg: none mean?

It marks an unsigned token. Servers should reject it unless they explicitly expect unsigned tokens, which is almost never the case.

Why is my token's expiry date thousands of years away?

The issuer stored exp in milliseconds instead of seconds. JWT time claims are NumericDates in seconds, so divide by 1000 when creating them.

Can it decode encrypted tokens (JWE)?

No. A JWE has five parts and its payload is encrypted, so it cannot be read without the decryption key. The tool recognises the format and tells you.

Should I store JWTs in localStorage or cookies?

An HttpOnly, Secure, SameSite cookie is safer in most web apps because page scripts cannot read it, which limits the damage of a cross-site scripting bug. localStorage is simpler but exposes the token to any script running on the page.

Is an OAuth access token always a JWT?

No. Some providers issue JWT access tokens and others issue opaque strings that only the authorisation server can interpret. OpenID Connect ID tokens, by contrast, are always JWTs.

How long should a JWT be valid?

Keep access tokens short-lived, typically minutes rather than days, because a JWT cannot easily be revoked before it expires. Use refresh tokens or a new sign-in to issue fresh ones.

More free tools.

All tools

Need tooling like this inside your product?

We build internal tools, developer platforms and APIs. Tell us what your team keeps doing by hand.