Sign a JSON Web Token with HS, RS, PS or ES, generate a key pair, and check the result against the verifier
Initializing in your browser…
Decode a JSON Web Token and, given the secret or public key, actually verify its signature. Refuses alg: none and algorithm confusion
Add your signature to PDF documents. Draw, type, or upload your signature, then position it anywhere on the page. Perfect for contracts, agreements, and official documents.
Build a colour harmony that holds its lightness by rotating hue in OKLCH, with the contrast of every pair, a perceptually even tint and shade ramp, and what a colour blind reader sees
You are testing an authorization guard and need a real signed token with a specific subject, an hour of validity, and the key id your server matches on.
Settings
alg HS256
secret a-development-secret-of-at-least-32-bytes (read as text)
kid key-2026-01
payload {"sub":"user_42","role":"admin","iat":1700000000,"exp":1700003600}Signed token, 196 characters
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImtleS0yMDI2LTAxIn0 .eyJzdWIiOiJ1c2VyXzQyIiwicm9sZSI6ImFkbWluIiwiaWF0IjoxNzAwMDAwMDAwLCJleHAiOjE3MDAwMDM2MDB9 .64-aXuzcAlKBrV_UZNCq3nhdUCRIthvTbCFqjRHXt8k
The three parts are the header, the payload and the HMAC-SHA256 of the first two joined by a dot, each in base64url. The kid ends up in the header, which is how a server holding several keys picks the right one. Two things this checks that most builders do not: how the secret should be read, because a secret published as base64 signed as its own characters produces a token the issuing service rejects and the failure looks exactly like a wrong secret, and whether the key is long enough, because RFC 7518 wants at least 256 bits for HS256 and a shorter one still produces a signature that verifies. RS, PS and ES are offered too, with a key pair generator, so the tool hands you the public key to give to whoever verifies.
Mint a signed JSON Web Token: pick an algorithm, supply a key, edit the claims as JSON, and the token is rebuilt as you type. Twelve algorithms are offered, HS256/384/512, RS256/384/512, PS256/384/512 and ES256/384/512, and for the asymmetric ones the tool will generate a key pair so you get both the private key it signs with and the public key to give to whoever verifies. `alg: none` is deliberately not on the list.
Two things decide whether a token you build here will actually be accepted, and both of them are usually left silent.
The first is how the secret is read. Most services publish an HMAC secret in base64, and their server decodes it to bytes before signing. A builder that always reads the secret as text signs against completely different bytes, so the token is well formed, verifies against itself, and is rejected by the service, and the failure looks exactly like a wrong secret. The encoding is therefore a setting here (text, base64, base64url or hex), the panel states how many bytes the key turned out to be and which reading produced them, and the tests check that a base64 secret read as base64 gives a token node:crypto verifies against the decoded bytes while the same secret read as text does not.
The second is key length. RFC 7518 section 3.2 says a key at least as large as the hash output MUST be used, so 256 bits for HS256, 384 for HS384 and 512 for HS512. A shorter key still produces a signature that verifies perfectly well, which is exactly why nobody notices; the tool signs anyway and says so, with the numbers. There is a generator that produces a secret of the right length.
The algorithm in the header is not a field you can edit: it is written from the algorithm the signature was actually made with, so the two can never disagree. That matters because a token whose header claims one algorithm and whose signature is another is what a confused verifier trips over, and it is the shape of the algorithm confusion attack the decoder refuses. A key id can be set and goes into the header, which is how a server holding a JWKS picks which key to check against.
The payload is edited as JSON and checked against RFC 7519 section 4.1 as you type, without ever refusing to build: exp, nbf and iat have to be numbers of seconds rather than strings or milliseconds; iss, sub and jti have to be strings; aud has to be a string or an array of strings; and the tool points out an exp that has already passed, an nbf in the future, an exp that is not after iat, and a payload with no exp at all. Minting an already-expired token on purpose is a legitimate thing to want, so those are notes rather than refusals.
Every token is signed with the platform’s Web Crypto and then decoded and verified again with the same verifier the decoder tool uses, and the panel reports the result while being clear about what that proves: it is the tool checking itself, not evidence your server will agree. The tests go further and verify every token with node:crypto, a different implementation, in both directions.
Signing is asynchronous and several runs can be in flight while you type. Each run carries a sequence number and only the latest may write its result, so the token on screen always belongs to the payload in the box rather than to whichever run happened to finish last. Thirty rapid payload changes in the browser tests end with the token matching the thirtieth.
Mint a token with the exact claims a route expects, or deliberately expire it, and watch the guard accept or reject it.
If a service rejects your token, try the same secret read as base64 rather than text. That one setting is the usual cause, and the two tokens are visibly different.
Generate a key pair, sign with the private key here, and give the public key to the verifier. Nothing that can mint a token ever leaves this page.
Build the exact token an API doc shows, with a kid and the claims it lists, and confirm it verifies before publishing it.
How the secret is read. Most providers publish it in base64, and signing it as text uses different bytes entirely. Switch the encoding and compare the two tokens; they will not be the same.
Because it does work. A short HMAC key produces a valid signature, so nothing breaks and nothing tells you. RFC 7518 section 3.2 requires a key at least the size of the hash output, and the warning gives you both numbers.
No. It is not on the list. A token with alg: none carries no signature at all and any verifier that honours it accepts anything the sender wrote; there is no legitimate reason to mint one here.
That is PKCS#1, and Web Crypto only reads PKCS#8. The error message gives you the openssl command to convert it: openssl pkcs8 -topk8 -nocrypt -in key.pem -out key8.pem
No, and it says so. It means this tool signed a token and then verified it with its own verifier, so the two halves agree. Paste the token into a decoder of your own before relying on it.
Nothing is sent anywhere and the whole thing runs in the page. That said, a production signing key does not belong in a browser tab; if the verifier is not you, use RS, PS or ES so only the public key has to travel.
Conversions run on your device in JavaScript. The values you enter are never sent over the network.