πŸ” JWT Encoder

Build and sign a JSON Web Token with HS256 for local testing β€” everything happens in your browser via the Web Crypto API, nothing is sent anywhere. For testing only β€” don't paste real production secrets into any web page, this one included.

Signing…

What gets signed

Your header and payload are parsed as JSON, re-serialised compactly and Base64URL-encoded with the = padding stripped. Those two strings, joined by a dot, are the signing input. Web Crypto imports the secret as raw UTF-8 bytes for HMAC-SHA-256 and signs that string; the 32-byte result becomes the 43-character third segment.

signature = HMAC-SHA256(base64url(header) + "." + base64url(payload), secret)
token     = header . payload . signature

With the defaults here - secret test-secret, iat 1700000000, which is 2023-11-14T22:13:20Z - the token ends Zqg7Fwu9OuZLhOkGDCZ67akZLCn3NsGJwA0pQPPwla4. Change one character of the secret and every character of that segment changes.

Using it safely

Use throwaway secrets only. A real signing key typed into any web page has passed through a text field and an autofill store; treat one pasted here as burned and rotate it.

Frequently asked questions

Is it safe to sign a JWT in the browser?

For test tokens, yes - signing runs locally through Web Crypto and no request leaves the page. For production, no: the secret would have to be shipped to every visitor, and whoever holds it can mint tokens for any user.

Why is my alg still HS256 after I changed it?

The script sets alg to HS256 on the header object just before encoding, because HMAC-SHA-256 is the only algorithm implemented here. RS256 and ES256 need a private key rather than a shared string.

How long should an HS256 secret be?

RFC 7518 requires at least 256 bits - 32 bytes - for HS256. Short words like the default here can be brute-forced offline in seconds against any token you hand out.