JWT Decoder and Verifier

Paste a JSON Web Token to decode its header and payload, read exp, iat and nbf as real dates, and verify the signature with a secret or public key. Decoding and verification happen in your browser — the token is never uploaded.

Verify signature

Supported: HS256, HS384, HS512 (shared secret) · RS256, RS384, RS512, PS256, PS384, PS512, ES256, ES384, ES512 (PEM PUBLIC KEY or RSA PUBLIC KEY, JWK, or JWKS — the key with the token’s kid is used). Uses the browser’s WebCrypto API; nothing is sent anywhere.

How to decode a JWT

A JSON Web Token is three Base64URL strings joined by dots: header.payload.signature. Decoding simply reverses the Base64URL encoding of the first two parts to reveal JSON — no key is needed, which is exactly why a JWT payload must never hold secrets. Paste a token above (with or without the Bearer prefix) and the decoder shows:

How to verify a JWT (JWT verify)

Verifying proves the token was issued by someone holding the key and has not been modified. It has two parts, and a backend must do both on every request:

  1. Signature: recompute the signature over header.payload with the expected algorithm and key, and compare. In the panel above, paste the HMAC secret for HS* tokens, or the issuer’s public key for RS*, PS* and ES* tokens. Identity providers publish these keys at a JWKS URL, typically https://<issuer>/.well-known/jwks.json; paste the whole JWKS and the matching kid is chosen for you.
  2. Claims: reject the token if exp is in the past or nbf in the future (allow a small clock skew, usually 30–60 seconds), and check that iss and aud match what your service expects.

Always pin the algorithm on the server side. Accepting whatever alg the token declares enables the classic attacks: alg: none tokens with no signature, and HS256 tokens “signed” with an RSA public key used as an HMAC secret.

Registered JWT claims (RFC 7519)

ClaimNameWhat to check
issIssuerExactly equals your identity provider’s issuer URL
subSubjectThe user or client ID the token represents
audAudienceContains your API’s identifier (string or array)
expExpiration timeSeconds since epoch; reject when now ≥ exp
nbfNot beforeReject when now < nbf
iatIssued atUseful for max-age policies and debugging clock skew
jtiJWT IDUnique ID for replay detection or revocation lists

Timestamps are Unix seconds. To convert one by hand, use the Unix timestamp converter.

JWT signing algorithms compared

algTypeVerify withTypical use
HS256 / 384 / 512HMAC + SHA-2The same shared secretSingle service that both issues and checks tokens
RS256 / 384 / 512RSA PKCS#1 v1.5Public key (PEM / JWK)Auth0, Okta, Cognito, Azure AD, Google, Keycloak
PS256 / 384 / 512RSA-PSSPublic keyOpen Banking, FAPI profiles
ES256 / 384 / 512ECDSA P-256 / P-384 / P-521Public keyApple, mobile and IoT, smaller signatures
noneUnsigned—Never accept in production

Decode and verify JWTs in code

JavaScript (Node.js, jose)

import { jwtVerify, createRemoteJWKSet, decodeJwt } from "jose";
decodeJwt(token);                                   // decode only, no verification
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: "api.example.com", algorithms: ["RS256"],
});

Python (PyJWT)

import jwt
jwt.decode(token, options={"verify_signature": False})          # decode only
jwt.decode(token, "your-256-bit-secret", algorithms=["HS256"])   # verify HS256
jwt.decode(token, public_key_pem, algorithms=["RS256"], audience="api.example.com")

Java (jjwt)

Claims claims = Jwts.parser()
    .verifyWith(Keys.hmacShaKeyFor(secret.getBytes(StandardCharsets.UTF_8)))
    .build()
    .parseSignedClaims(token)
    .getPayload();

Go (golang-jwt)

tok, err := jwt.Parse(s, func(t *jwt.Token) (any, error) {
    return []byte("your-256-bit-secret"), nil
}, jwt.WithValidMethods([]string{"HS256"}), jwt.WithAudience("api.example.com"))

Bash (decode only)

cut -d. -f2 <<< "$TOKEN" | tr '_-' '/+' | base64 -d 2>/dev/null | jq .

Common questions

Is it safe to paste a JWT into this decoder?

Decoding and verification run entirely in your browser; the token, secret and key are never sent over the network or stored. Still, treat a live token like a password — prefer expired or test tokens, and revoke any production token you have shared.

Does decoding a JWT verify it?

No. Decoding is just Base64URL, which anyone can do. A token is trustworthy only after its signature is verified with the right key and its exp, nbf, iss and aud are checked.

How do I verify a JWT signature?

For HS256/384/512 paste the shared secret (tick Base64-encoded if it is stored that way). For RS, PS and ES algorithms paste the public key as PEM, a JWK or a whole JWKS; the key matching the token’s kid is used.

Why is exp such a big number?

exp, iat and nbf are seconds since 1 January 1970 UTC — Unix timestamps. The claim table shows each as a date in UTC, IST and your local time, with how long ago or ahead it is.

What is the difference between HS256 and RS256?

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

Can I edit the claims and re-sign the token?

Changing any character of the header or payload breaks the signature. Issuing a new valid token needs the secret or private key, which only the issuer should hold — do it in server code with a JWT library.

Is the JWT payload encrypted?

No. A signed JWT is only Base64URL-encoded, so anyone holding it can read the claims. Encrypted tokens (JWE) have five parts instead of three and cannot be decoded without the key.