DevToolsmith

JWT Decoder and Signature Verifier

Paste a JSON Web Token to see its header and payload, with standard claims explained and timestamps shown as dates. Check whether it has expired, and verify the signature with a secret, PEM public key or JWKS.

Runs 100% in your browser — nothing is uploaded

alg: HS256
Header
{
  "alg": "HS256",
  "typ": "JWT"
}
Payload
{
  "sub": "1234567890",
  "name": "John Doe",
  "iat": 1516239022
}

Claims

sub1234567890Subject — who the token is about (usually a user ID)
nameJohn DoeFull name
iat2018-01-18T01:30:22ZIssued at

Verify signature

Enter the shared secret the token was signed with.

Structure of a JWT

A JWT has three parts, each base64url-encoded and separated by a dot:

  • Header: the signing algorithm (alg), token type and often a key ID (kid).
  • Payload: the claims, such as who the user is, who issued the token and when it expires.
  • Signature: computed over header.payload with the issuer's key. If one character of the header or payload changes, verification fails.

Registered claims

ClaimNameMeaning
issIssuerWho issued the token. Check it matches your identity provider.
subSubjectThe user or entity the token represents.
audAudienceWhich API the token is for. Reject tokens meant for other services.
expExpirationUnix time (seconds) after which the token is invalid.
nbfNot beforeUnix time before which the token is invalid.
iatIssued atWhen the token was created.
jtiJWT IDUnique ID, useful for revocation lists and replay protection.

Verifying JWTs in your code

Decoding is not verifying. In your backend, always verify the signature, pin the allowed algorithms, and check exp, iss and aud:

Node.js (jose)

// npm install jose
import { createRemoteJWKSet, jwtVerify } from 'jose';

const JWKS = createRemoteJWKSet(new URL('https://issuer.example.com/.well-known/jwks.json'));

const { payload } = await jwtVerify(token, JWKS, {
  issuer: 'https://issuer.example.com/',
  audience: 'my-api',
  algorithms: ['RS256'],   // never let the token choose
});

Python (PyJWT)

# pip install "pyjwt[crypto]"
import jwt

payload = jwt.decode(
    token,
    key=public_key_pem,
    algorithms=["RS256"],
    audience="my-api",
    issuer="https://issuer.example.com/",
)

Command line

# Decode the payload without verifying (bash + jq)
echo "$TOKEN" | cut -d. -f2 | tr '_-' '/+' | base64 -d 2>/dev/null | jq .

Common JWT security mistakes

  • Accepting alg: none or letting the token's header choose the algorithm. Always pass an explicit allow-list of algorithms.
  • Algorithm confusion: verifying an RS256 public key as if it were an HS256 secret lets attackers forge tokens. Bind each key to one algorithm.
  • Weak HMAC secrets: HS256 secrets should be at least 256 bits of randomness, not a password.
  • Storing tokens in localStorage: any XSS bug can steal them. Prefer HttpOnly, Secure cookies.
  • Long lifetimes: JWTs can't easily be revoked, so keep access tokens short-lived.

Frequently asked questions

How do I decode a JWT?

Paste the token into the box above. A JWT has three base64url-encoded parts separated by dots: header, payload and signature. The tool decodes the header and payload to JSON, explains standard claims, and shows exp, iat and nbf as readable dates. You can also paste a whole "Authorization: Bearer …" value.

Is it safe to paste a JWT into this site?

Decoding and verification run entirely in your browser with the Web Crypto API. The token and keys are never sent anywhere, and there is no share-link feature for this tool. Still, a valid JWT is a credential: prefer expired or test tokens, and never paste private keys.

Can anyone read the data in a JWT?

Yes. A signed JWT (JWS) is encoded, not encrypted, so anyone with the token can read its claims. The signature only proves it hasn’t been modified. Never put secrets or sensitive personal data in a JWT payload. If the payload must be confidential, use an encrypted JWT (JWE).

What is the difference between HS256 and RS256?

HS256 uses one shared secret to both sign and verify, so every service that verifies tokens could also forge them. RS256, ES256 and PS256 sign with a private key and verify with a public key, so you can safely publish the public key, for example through a JWKS endpoint. Identity providers like Auth0, Okta, Cognito and Entra ID use RS256 by default.

Why does my token show as expired?

The exp claim is a Unix timestamp in seconds. Once the current time passes it, servers must reject the token. Access tokens are usually short-lived (5–60 minutes) and are renewed with a refresh token. Also check for clock skew between servers, which libraries usually tolerate with a small leeway.