JWT Decoder
Decode a JWT header and payload in your browser, check exp/nbf/iat dates and verify HS256/384/512 or RS256/384/512 signatures. Tokens stay on your device.
Your inputs and files stay in your browser
Paste a JWT (header.payload.signature) or load a demo token.
- Header
- Payload
- Signature
Verify Signature
The header, payload and time claims appear here once you paste a token.
Time checks do not establish authenticity.
On this page
Paste a JSON Web Token to see its header and payload as formatted JSON, the signing algorithm and when the token was issued, becomes valid and expires. Optionally verify the signature with a shared secret or an RSA public key.
Detailed Functionality
Decoding happens as you type: the header and payload are base64url-decoded and pretty-printed in the token's original claim order. A leading Bearer and line breaks copied from an HTTP header are stripped automatically. The registered time claims exp, nbf and iat are shown as dates in your local time zone, and an expired or not-yet-valid token is flagged.
Signature verification runs in a Rust cryptography module compiled to WebAssembly and uses the algorithm named in the token header: HS256, HS384 and HS512 with a shared secret (used as UTF-8 text), RS256, RS384 and RS512 with an RSA public key in PEM (BEGIN PUBLIC KEY or BEGIN RSA PUBLIC KEY). Paste a JWK or a JWKS (for example from an identity provider's /.well-known/jwks.json) instead, and the key is picked by the token's kid (without kid, every key that fits the algorithm is tried) and checked with the browser's Web Crypto API — this also covers PS256/384/512, ES256/384/512 and EdDSA (Ed25519). A token with alg: none is always reported as unsigned, never as valid.
Tokens and keys stay in the page: nothing is sent to a server or saved. Remember that decoding proves nothing about authenticity — only a verified signature does.
Practical Examples
jwt.io sample: the token eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIi… decodes to the header {"alg":"HS256","typ":"JWT"} and a payload with sub, name and iat; the secret your-256-bit-secret gives “Signature Verified”, any other secret “Invalid Signature”.
Expired token: a payload with "exp": 1767225600 is marked as expired on 1 January 2026 (shown in your local time zone).
From an Authorization header: paste Bearer eyJ… as is — the prefix and line breaks are removed before decoding.
Unsigned token: eyJhbGciOiJub25lIn0.eyJzdWIiOiIxIn0. decodes to {"alg":"none"} and {"sub":"1"} and is reported as unsigned and not to be trusted.
How to Use This Tool
Paste the token
Paste the JWT into Encoded JWT; decoding starts immediately.
Read the header and payload
Check the formatted Header and Payload, the algorithm badge and the issued/valid/expires dates under the payload.
Verify the signature
In Verify Signature, enter the HMAC secret or the PEM public key into Secret / RSA public key. The status shows whether the signature is valid.
Tips and Best Practices
- Anyone can decode a JWT: never put passwords or other secrets in the payload.
- The HMAC secret is used exactly as typed. If your backend stores it base64-encoded, decode it first — pasting the base64 string gives “Invalid Signature”.
- For RS* tokens paste the public key, not the private key; an X.509 certificate is not accepted, extract its public key first.
- Expiry is compared with your device clock, so a wrong system time gives a wrong “Expired” mark.
- Need a token to test with? Create one in the JWT Encoder.