Paste a JSON Web Token and it is split into Header, Payload and Signature as you type; whitespace and a leading Bearer are ignored. Header and payload appear as formatted JSON with numbers and strings exactly as in the token. The Claims table shows exp, nbf and iat as dates in your browser’s time zone with UTC on a second line, with relative time, and explains iss, sub, aud and jti.
A status line says Expired, Not valid yet or Within its validity period, plus “Signature not verified” until a check succeeds. Warnings flag alg none, a missing exp, an exp more than a year ahead and time claims that are not numbers. Errors name the part and the position.
Verify signature checks HS256/384/512 against a secret (text or base64), and RS, PS, ES and EdDSA (Ed25519) against a public key as PEM or JWK, using the browser’s Web Crypto API. Everything runs in your browser; nothing is uploaded or stored in the URL or browser storage, and Clear wipes it. Even so, do not paste production secrets or live tokens into any website.
Example
Token from RFC 7519 section 3.1:
eyJ0eXAiOiJKV1QiLA0KICJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ.dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk
Header:
{
"typ": "JWT",
"alg": "HS256"
}
Payload:
{
"iss": "joe",
"exp": 1300819380,
"http://example.com/is_root": true
}
The Claims table shows exp as 22 March 2011, 18:43:00 UTC (and in your local time above it), so the status reads Expired.
Verify a JWT in code
Always pin the accepted algorithm, and check the claims your service depends on.
import { jwtVerify } from "jose";
const secret = new TextEncoder().encode(process.env.JWT_SECRET);
const { payload } = await jwtVerify(token, secret, {
algorithms: ["HS256"],
issuer: "joe",
});
import jwt
payload = jwt.decode(
token,
secret,
algorithms=["HS256"],
options={"require": ["exp"]},
)
import "github.com/golang-jwt/jwt/v5"
token, err := jwt.Parse(tokenString, func(t *jwt.Token) (any, error) {
return []byte(secret), nil
}, jwt.WithValidMethods([]string{"HS256"}))
if err != nil || !token.Valid {
// reject
}
Limitations
- Encrypted tokens (JWE, five parts) are recognised and their header is shown, but they cannot be decrypted.
- The tool does not create or sign tokens.
- It does not fetch keys from a JWKS URL or an issuer. Paste the key yourself; from a JWK Set, copy one key.
- Private keys are rejected. PKCS#1 (
BEGIN RSA PUBLIC KEY) and X.509 certificates are not accepted; convert them to SPKI (BEGIN PUBLIC KEY). - ES256K and Ed448 are not supported. ES signatures must be raw r‖s, as JWS requires, not DER.
- EdDSA needs a browser whose Web Crypto supports Ed25519: Chrome 137, Firefox 129 or Safari 17 and later.
- Validity status uses your device clock.
issandaudare shown, not checked.
FAQ
Is decoding a JWT the same as verifying it?
No. Anyone can read the header and payload. Only a signature check with the right secret or public key shows the token was not altered, and your server must also check exp, iss and aud.
What do exp, nbf and iat mean?
They are NumericDate values (RFC 7519 sections 2 and 4.1): seconds since 1970-01-01T00:00:00Z UTC, ignoring leap seconds. exp is when the token stops being acceptable, nbf is the time before which it must not be accepted, and iat is when it was issued.
Is a JWT encrypted?
A normal signed JWT (JWS) is not. The parts are base64url, an encoding, so the payload is readable by anyone who holds the token. The encrypted form is JWE, which has five parts.
What does alg “none” mean?
The token is unsecured: the signature is empty (RFC 7519 section 6) and nothing proves who made it. A server should reject it by accepting only the algorithms it expects. The tool warns when it sees it.
HS256 or RS256?
HS256 uses one shared secret to sign and to verify, so every verifier can also forge tokens. RS256 uses a key pair: the issuer signs with the private key and verifiers need only the public key.