ToolsOps

Security

JWT decoder and verifier (HS256, RS256, ES256)

Paste a JWT and the tool splits header, payload, and signature, decodes base64url and shows the JSON with syntax highlight. It interprets the temporal claims (iat, nbf, exp) in your local timezone and flags whether the token is currently valid. To verify the signature, paste your HMAC secret or your public key in PEM or JWK format. Verification runs locally with Web Crypto API; no token, secret, or key is sent to a server.

The token is processed locally. It is not sent to any server.
The link only serializes UI options (tab, algorithm filter, secret format). It never includes the token, secret, or keys.

Examples

  • Paste a JWT and the Decode tab splits the three parts.Decode header and payload
  • Switch to Verify signature, UTF-8 format, paste the shared secret.Verify HS256
  • Paste the public key inside -----BEGIN PUBLIC KEY-----.Verify RS256 with PEM
  • Paste the JWK from your identity provider's JWKS ({"kty":"EC","crv":"P-256",...}).Verify ES256 with JWK
  • See the badge next to exp in the claims panel.Check expiration

Frequently asked questions

Does my data leave the browser?
No. Decoding runs locally with atob and JSON.parse; signature verification runs locally with Web Crypto API. No token, secret, or key is sent to a server. Verify it by opening DevTools on the Network tab while using the tool.
Why is decoding not the same as verifying?
Decoding a JWT only reads its content by parsing base64url. Anyone can craft a JWT with arbitrary claims. What matters for trusting a token is that its signature is valid with the right key. Use the 'Verify signature' panel with the secret or public key.
Which algorithms does verification support?
HS256, HS384 and HS512 (HMAC with a shared secret). RS256, RS384 and RS512 (RSA with public key in PEM or JWK). ES256, ES384 and ES512 (ECDSA over P-256, P-384 and P-521 respectively). The RFC also defines `alg: none`, which the tool actively rejects because it has been a historical attack vector.
Why is `alg: none` rejected?
RFC 7515 §4.1.1 permits `alg: none` for unsigned tokens, but it has been one of the most common causes of authentication bypass: a library accepts the token without verifying anything when the header says none. The tool never marks such a token as a valid signature, regardless of what you paste in the secret/key field.
What happens if the token is expired?
The exp claim is rendered as a timestamp in your local time and labeled with the delta (expired 3 hours ago). The signature may still be cryptographically valid, but a server honoring RFC 7519 must reject an expired token. The tool signals both facts separately so you can distinguish between signature OK and token acceptable.
Can I paste the secret as hex or base64 instead of UTF-8?
Yes. The 'Secret format' selector switches between UTF-8 (default, what you see), hex (hex pairs), and base64. For HS256 with a key generated with `openssl rand -base64 32`, base64 is the natural choice.
Do you support JWE (encrypted tokens)?
Not in v1. JWE (5 parts, encrypted payload) requires symmetric or asymmetric decryption in addition to verification. It is being evaluated for a future iteration if real demand (measured in GSC) justifies it. The tool detects the 5-part JWE format and shows a clear unsupported message.
Where should I store a JWT in my application?
For typical web apps: an HttpOnly cookie with Secure and SameSite Lax or Strict. Avoid localStorage due to XSS exposure. For SPAs with a separate backend: HttpOnly cookies when possible; otherwise, access token in memory and refresh token in an HttpOnly cookie. The 'JWT best practices' editorial guide covers this in more detail.