What Is a JWT? Structure, Claims and Decoding

A JWT (JSON Web Token) is a compact, URL-safe string of three base64url parts separated by dots: a header naming the algorithm, a payload of claims such as sub and exp, and a signature. Anyone can decode and read the payload; only the signature, checked with the right key, proves nobody changed it.

Registered claim names (RFC 7519, section 4.1)
ClaimNameMeaning
issIssuerWho issued the token
subSubjectWho the token is about, usually a user id
audAudienceWhich recipients should accept it
expExpiration timeReject on or after this time
nbfNot beforeReject before this time
iatIssued atWhen the token was created
jtiJWT IDA unique id, useful for blocking reuse

Updated

Paste a token into the decoder below to see its header and payload, with each registered claim explained and every timestamp turned into a readable date. Decoding happens in this page's own JavaScript, so the token is never uploaded. That matters, because a live token is a key to someone's account.

Private JWT decoder

Paste a token to read its header and payload. Decoding runs in your browser; the token is not sent, stored or logged.

Decode and verify in code

Decode a payload in plain JavaScript

Reads the claims without verifying them. Fine for showing a username in the UI, never for deciding access.

function decodeJwtPart(part) {
  const b64 = part.replace(/-/g, "+").replace(/_/g, "/").padEnd(Math.ceil(part.length / 4) * 4, "=");
  const bytes = Uint8Array.from(atob(b64), (c) => c.charCodeAt(0));
  return JSON.parse(new TextDecoder().decode(bytes));
}

const [header, payload] = token.split(".").slice(0, 2).map(decodeJwtPart);
const expired = payload.exp * 1000 < Date.now();

Verify on the server with jose

jwtVerify checks the signature, exp and nbf, and with these options also the issuer, audience and the allowed algorithm.

import { jwtVerify } from "jose";

const secret = new TextEncoder().encode(process.env.JWT_SECRET);

const { payload } = await jwtVerify(token, secret, {
  algorithms: ["HS256"],
  issuer: "https://auth.example.com",
  audience: "my-api",
});
console.log(payload.sub);

The three parts

The header is a small JSON object such as {"alg":"HS256","typ":"JWT"}. The payload holds the claims. Each is base64url encoded, which is base64 with - and _ instead of + and / and no = padding, so the result is safe in URLs and headers.

The signature is computed over the first two encoded parts joined by a dot. Change one character of the payload and the signature no longer matches.

Signing algorithms

HS256 uses one shared secret both to sign and to verify, so every service that checks tokens can also mint them. RS256 and ES256 sign with a private key and verify with a public key, which suits setups where many services verify but only one issues.

Pitfalls that still cause breaches

Unsecured tokens with alg none carry no signature at all. A library that trusts the header can be tricked into accepting one, or into treating a public RSA key as an HMAC secret. RFC 8725 tells libraries to let the caller fix the allowed algorithms, and you should.

How it works

  1. The decoder splits the token on its dots and expects three parts (a JWE with five parts is encrypted and cannot be read).
  2. It turns the first two parts from base64url back into text and parses them as JSON.
  3. Registered claims get a label, and exp, nbf and iat are shown as dates with whether the token is currently valid.
  4. The signature is shown but not checked: that needs the issuer's key, which belongs on your server.

Tips

Frequently asked questions

Is it safe to decode a JWT online?

Only if decoding happens in your browser. The token is a credential: anyone holding a valid one can call the API as that user until it expires. This page's decoder runs locally and sends nothing, but for production tokens the safest habit is to decode test tokens only.

Is a JWT encrypted?

A normal signed JWT (a JWS) is not. Its payload is only base64url encoded, which anyone can reverse. Encrypted tokens exist as JWE, with five dot-separated parts instead of three, but most login and API tokens are signed, not encrypted.

What format are exp and iat in?

NumericDate: whole seconds since 1970-01-01T00:00:00Z, ignoring leap seconds. JavaScript's Date.now() returns milliseconds, so divide by 1000 before comparing, a very common bug.

Should I store a JWT in localStorage or a cookie?

Any script running on the page can read localStorage, so one cross-site scripting bug can steal the token. An HttpOnly, Secure, SameSite cookie keeps it away from scripts, at the cost of handling CSRF. Many teams choose the cookie for browser sessions.

Can I log a user out with a JWT?

Not by itself, because the token stays valid until exp. Use short expiry plus refresh tokens you can revoke, or keep a deny list of jti values for tokens that must die early.

Related: JWT generator, OAuth explained, Website authentication guide, JSON formatter, Next.js authentication.

Start for free or see all free tools. We.Inc is free to start, with no card needed. AI building is on paid plans from $20 a month.

More in Guides

We.Inc is an AI-powered website builder you can resell under your own brand. Launch a branded client dashboard, bill on Stripe Connect, and deliver AI-generated websites in minutes. White-label plans start at $99 a month for 25 client sites, with a 7-day free trial and no per-site fees.

Product

Who It's For

Features

Resources

Company

View Sitemap