JWT Encoder
Sign and encode JSON Web Tokens — HS256, HS384, HS512.
How to use JWT Encoder
- Edit the Header JSON or leave the default `{"alg":"HS256","typ":"JWT"}`.
- Edit the Payload JSON — add sub, iat, exp, and any custom claims.
- Paste your shared secret into the Secret field. Toggle Show to reveal it.
- Pick the HMAC algorithm — the header's alg field auto-updates to match.
- Copy the encoded token with the Copy button, or share the JSON state with Share (the secret is never shared).
JWT Encoder
A fast, private JWT signer that turns a header, a payload, and a shared secret into a spec-compliant JSON Web Token. Signing runs 100% in your browser via the Web Crypto API. Your secret never leaves your machine, and no bytes are uploaded anywhere.
Why another JWT encoder?
Because most of the ones that rank for "JWT encoder" are happy to ship your secret to a server the moment you paste it. That's convenient for them — they get a free stream of leaked credentials — and catastrophic for you. Shared secrets are the entire point of the HMAC family; whoever holds the secret can forge any token they want for the lifetime of that key. Pasting one into a random web tool that happens to top the Google results is strictly worse than pasting a password there: one leaked HS256 secret unlocks every JWT your service has ever minted with that key, for as long as rotation hasn't happened yet.
This tool runs the entire signing pipeline client-side. TextEncoder serialises the JSON segments to UTF-8, crypto.subtle.importKey("raw", …, { name: "HMAC", hash: "SHA-256" }, …) wraps your secret as a non-exportable CryptoKey, crypto.subtle.sign computes the HMAC, and a few lines of base64url arithmetic emit the compact JWS form. There is no network call in the signing path, no analytics hook on the secret input, and no third-party script in the chain between your clipboard and the encoded token.
What it does
- HS256 / HS384 / HS512 signing. All three HMAC variants from RFC 7518 §3.2, implemented via Web Crypto so the hash primitive is the one the platform already trusts for TLS.
- Spec-compliant base64url encoding. Both segments are JSON-serialised with no whitespace before encoding — this is a frequent source of subtle signature mismatches when an implementation pretty-prints the JSON and then hashes the pretty form. The
=padding is stripped and+//are replaced with-/_per RFC 7515 §3. - Live JSON validation. Header and payload editors flag syntax errors inline as you type, without blocking the rest of the UI.
- Color-coded token display. The encoded token is rendered with the same three-color convention jwt.io popularised — red for the header segment, purple for the payload, and blue for the signature — so you can always tell at a glance which byte is which.
- Automatic alg sync. Switch the algorithm dropdown and the header's
algfield follows along, unless you've manually edited the header to something different (in which case you're in the driver's seat). - Claim inspector. A small side panel surfaces the common registered claims (
iss,sub,aud,iat,exp) with relative-time chips — "issued 2m ago", "expires in 45m" — so the token stays readable as you tweak the payload. - Shareable state. The Share button copies a URL that restores the algorithm + header + payload for a teammate. The secret is never stored in the URL fragment.
Privacy-first, offline-capable
After the first visit the entire page is cached, so the encoder works offline — useful at airports, in customer datacenters, on restricted networks that block jwt.io outright. Open the browser devtools Network tab while you sign a token and you'll see exactly zero outbound requests from the signing interaction itself.
The secret input is a standard <input type="password"> with a show/hide toggle, so shoulder surfing is at least a known risk rather than a surprise. The shared-state URL intentionally omits the secret. Analytics never see the secret, never see the payload, and never see the token.
What this tool deliberately doesn't do
- Asymmetric signing (RS256, PS256, ES256, EdDSA). These require PEM or JWK private-key import, which we want to build with care rather than ship as a checkbox. Use a server-side signer with a properly-stored private key until we ship the asymmetric variant.
- Key generation. The encoder takes a secret you already have. For generating new HMAC secrets use the Password Generator (pick 256 bits of entropy for HS256, 384 for HS384, 512 for HS512).
- Claim inference. We do not auto-inject
iat,exp, orjti— your payload is signed exactly as you wrote it. The UI warns about missing registered claims, but the transform stays unopinionated. - Token verification. Signing and verification are different trust decisions. Use the sibling JWT Decoder to inspect an existing token's claims; for actual verification use a server-side library (
jose,jsonwebtoken, PyJWT) with the issuer's key.
Related tools
- JWT Decoder — the direct counterpart. Paste a token, inspect its three parts, watch the expiry countdown. The decoder is what your consumers run; this encoder is what the issuer runs.
- SHA-256 Hash — if you are debugging a signing mismatch and want to confirm that the pre-signing bytes are what you think they are, hash the
header.payloadstring here and compare. - Base64 Encode / Decode — peel individual segments by hand when you want to see exactly what the raw JSON bytes look like before base64url.
When you need a signed JWT in the fewest keystrokes, this is the shortest private path: paste, pick, sign, copy.
Frequently asked questions
What signing algorithms does this JWT encoder support?
Version 1 supports the three HMAC-based JWS algorithms from RFC 7518 — HS256 (HMAC-SHA-256), HS384 (HMAC-SHA-384), and HS512 (HMAC-SHA-512). These are the right pick for machine-to-machine tokens where both sides already share a secret. Asymmetric algorithms (RS256, PS256, ES256, EdDSA) are intentionally out of scope for now because they require PEM or JWK private-key import, which is a significant safety and UX surface to expose in a client-side tool. The encoder's alg enum has a dedicated extension point so those can be added in a follow-up without reshaping the public API.
Is my signing secret safe when I paste it into this tool?
The secret stays entirely in your browser. Signing runs on the Web Crypto API (crypto.subtle.importKey then crypto.subtle.sign), which is the same implementation the platform uses for HTTPS itself. Nothing is uploaded, no analytics record the secret, and the secret is never encoded into the share URL — only the header, payload, and algorithm choice end up in the URL fragment when you click Share. That said, treat the secret exactly the way you'd treat any production credential — rotate it if you paste it into any tool you don't control end-to-end.
Does the header's alg field auto-sync with the algorithm dropdown?
Yes — if you switch the dropdown from HS256 to HS384 and your header still reads alg HS256, the header JSON is rewritten to alg HS384 for you. The moment you manually edit the header's alg to something else, the sync stops — the assumption is that you're deliberately crafting a token (perhaps to reproduce a real-world verifier bug) and we shouldn't stomp your edit. This matches the behaviour you'd want when bouncing between test vectors.
Why does the encoder warn me about missing iat, exp, or sub claims?
These are the three RFC 7519 registered claims that most JWT verifiers expect to see in practice. Without iat (issued-at) and exp (expires), a token can live forever unless it's explicitly revoked. Without sub (subject), some verifiers can't attribute the token to a principal. The warning is just a hint — the encoder will still sign whatever payload you give it — but it nudges you toward the common case before you paste the token into a real service.
Can I use this tool to mint a token I'll actually use in production?
You can, but it's not the recommended path. A browser-generated token carries whatever clock skew and clipboard hygiene your machine has at the moment you signed it. For production, mint tokens from the service that owns the signing key, with iat/exp derived from the server's clock and a revocation strategy in place. This tool is excellent for debugging — round-tripping a payload through a verifier, reproducing a test vector, crafting an intentionally-invalid token for negative tests — which is why it shares its UI language with the decoder counterpart.