A signed JWT is three base64url segments joined by dots: the header, the payload, and a signature over the first two exactly as encoded (RFC 7515). So what is signed is the compact JSON this page writes, not the text in the editors: whitespace is dropped and key order is kept. The header’s alg is set to the algorithm you choose, with a note if it said something else. alg "none" is refused, because an unsigned token is the original JWT vulnerability; to test that a server rejects one, the header and payload in base64url followed by a dot and nothing else is all it takes. A claim that appears twice is refused too, since JSON.parse keeps only the last and RFC 7519 requires names to be unique, and integers too large for JavaScript are flagged. HS256 output is checked against RFC 7515 Appendix A.1, RS256 against Appendix A.2, and HS256 tokens against this site’s own verifier.
HS256, HS384 and HS512 are HMAC with a shared secret, computed on this page. RFC 7518 §3.2 requires the key to be at least as long as the hash — 32 bytes for HS256, 64 for HS512 — and a shorter one is flagged, because it can be brute-forced offline from any single token. Anyone who can verify an HS token can also mint one. RS256 (RSASSA-PKCS1-v1_5, deterministic), PS256 (RSASSA-PSS with a 32-byte salt, so each signature differs) and ES256 (ECDSA on P-256) use the browser’s Web Crypto with a PKCS#8 private key; a PKCS#1 or SEC 1 key is refused with the openssl command that converts it. An ES256 signature must be the 64-byte R and S concatenated (RFC 7518 §3.4), which Web Crypto produces, and not the DER structure openssl dgst writes — the usual reason a hand-signed ES256 token fails elsewhere. Generate key pair makes RSA 2048 or P-256 keys in the page and shows the public key as PEM and as a JWK.
iat, nbf and exp are NumericDates: seconds since 1970, not the milliseconds Date.now() returns. The helpers write iat as now and exp as iat plus a duration such as 15m, 1h30m, 7d or PT1H; a bare number is read as seconds, although jsonwebtoken reads the string "120" as 120 milliseconds. Milliseconds, a missing exp and claims named like passwords or keys are all flagged, because a JWT is signed, not encrypted — anyone holding it can read the payload. Secrets and keys never leave the page; a browser test checks that no request carries them. Not supported: encrypted tokens (JWE), ES384, ES512 and EdDSA.