HS256 · HS384 · HS512

JWT encoder and signer

Write the claims, pick a hash, and sign an HMAC token with a secret that never leaves this tab.

Filled in, it writes iat and exp for you.

These four fields cover the usual token. Anything else — aud,roles, a custom claim — belongs in the JSON view, which keeps whatever you add there.

The secret and the claims stay in this tab. Signing uses WebCrypto on a non-extractable key and makes no network request.

Short answer: paste the claims, type a secret, pressSign token. You get the compact JWS and its three segments, and the page tells you if the key is too short to take seriously.

What the signature covers

A JWS signs base64url(header) + "." + base64url(payload) — the two encoded segments, byte for byte. That is why the header is built by this page rather than typed:alg can never disagree with the algorithm actually used, which is the classic JWT confusion bug where a verifier is told to trust the token’s own claim about how it was signed.

What this page will not do

Need to read a token you did not create? The JWT decoder shows the claims and says plainly that it verified nothing. Building the signature by hand is also possible: the HMAC generator produces the same bytes from the signing input shown above.

JWT signing questions

What does signing a JWT in a browser actually prove?

It proves the token was built by someone holding the secret, and that its header and payload were not modified afterwards. That is all a signature means. It says nothing about the claims being true — a token with sub: "admin" is only as trustworthy as the issuer’s own checks.

Why only HS256, HS384 and HS512?

Those three use a shared secret, which is a key a page can hold: it never leaves the tab, and WebCrypto signs with it in place. RS256 and ES256 need a private key, and a private key in a web page is a private key on the internet. For those, sign on a server and use this page only to inspect the result.

Is the secret stored anywhere?

No. It lives in a password field in this tab, is imported into a non-extractable CryptoKey for one call, and is discarded when the page reloads. There is no localStorage write, no cookie and no request carrying it.

How is this different from the decoder?

The decoder reads a token someone else issued and explicitly does not verify it. This page creates a token with a signature you can reproduce: the signing input is shown, so you can check it with openssl or your own library. Neither page ever claims a third-party token is valid.

Why does it warn about a short secret?

An HS256 signature is only as strong as its key. A short secret can be brute-forced offline from one token, so the page states the length of the key it used and marks anything under 32 bytes as too short for production.

Related tools