🪪 JWT Generator & Signer
Enter header, payload, and secret to produce a signed JWT entirely in your browser. Supports HS256 / HS384 / HS512 via Web Crypto API.
⚠️ Security Notes
• Secrets are processed entirely in your browser using Web Crypto API and are never sent to a server.
• Entering production secrets into web tools is generally not recommended. Use for testing, learning, and debugging.
• HS256 secrets should be at least 256 bits (32 bytes); HS512 should be at least 512 bits (64 bytes).
🔗 Related Tools
📖 Where people get stuck
Enter a header, a payload and a secret, and this produces a signed JWT in the browser using the Web Crypto API (HS256, HS384 or HS512). Buttons add claims such as iat and exp. The secret is never sent to a server. There is one thing to understand about JWTs before anything else — a JWT is not encryption. The payload is merely Base64URL encoded, and anyone without any key at all can read it. The signature guarantees only that the contents were not altered; it guarantees nothing whatsoever about them not being seen.
| Case | What happens | What to do |
|---|---|---|
| Pasting a production secret into a browser tool | This page does not send values to a server, but "not transmitted" and "leaves no trace" are different claims. The string you type exists in the DOM, may persist in browser history and autofill, appears in screenshots and screen shares, and is readable by any extension you have installed. Copy it and it lands in your clipboard history tool as well. The most commonly overlooked item is the generated token itself: a JWT pasted into Slack or a ticket for debugging remains usable for as long as it is valid, even if the secret never leaked — a JWT is a bearer token, so whoever holds it is treated as the subject. | Only put a throwaway secret into this page. A value from the random-generate button is enough — if the point is to confirm how signing works, it does not have to be real. If you have already pasted a production secret, there is exactly one remedy: rotate it now. Leaving it on the assumption that it is probably fine gives you no way to determine later whether it leaked — and an HMAC secret can be brute-forced locally from a single captured token, so dictionary words and short strings are especially dangerous. Better still, design things so that a production secret is never seen by a human at all — have it read directly from an environment variable or a secret manager, and never create a copy-and-paste path in the first place. |
exp only means something to the verifier |
exp is just a field; it is not a mechanism that makes a token stop working when the time arrives — it becomes an expiry only because the verifier reads the value and rejects the token. Four standard defects follow. (1) Forget exp and the token is valid forever. (2) Get the unit wrong — times in a JWT are seconds since the epoch, while JavaScript Date.now() returns milliseconds, so passing it straight through points fifty thousand years into the future. (3) Clock skew between servers causes a freshly issued token to be rejected on its nbf. (4) An issued token cannot be revoked — logging out or changing the password does not stop it; it stays valid until exp. |
Keep the exp of an access token short — fifteen minutes to an hour is the usual guidance. Maintain long-lived login state with a refresh token instead, stored server-side so it can be invalidated individually. That is the only way to address the revocation problem head-on. If immediate revocation is a requirement, include a jti and keep a denylist — but at that point you have given up the stateless-server advantage that motivated JWT in the first place, so check whether the requirement is real before you build it. In the verifier, allow a leeway of some tens of seconds when comparing exp and nbf. And always use seconds — in JavaScript, Math.floor(Date.now() / 1000). |
The verifier trusts the alg in the token |
The alg in the header sits in a place the attacker can rewrite — a library that reads it to decide how to verify is letting the attacker choose the verification method. Two well-known breaks exist. (1) alg: none — write the value meaning "unsigned" and leave the signature segment empty, and a naively implemented library accepts it. (2) RS256 and HS256 confusion — take a token meant to be verified with an RSA public key, rewrite alg to HS256 and sign it using the public key as the HMAC secret. Since the public key is public, the attacker can mint valid tokens at will. Both are implementation bugs, not flaws in JWT itself. |
In the verifier, pass the algorithm as a fixed value. Most libraries accept an argument such as algorithms: ['HS256'] — if the API lets you omit it, do not omit it. The alg you read from a token is not an input to verification; it is one of the things being verified. Pin the key in the same way, and if you rotate several keys, select by kid and always select from your own key set. Do not forget secret strength either: use at least 256 bits of randomness for HS256 and never a memorable password — HMAC can be verified offline as many times as the attacker likes from a single token, which makes dictionary attacks a realistic threat. And finally, do not write the library yourself. |
Do not put secrets in the payload. To repeat: anyone can read it — put an email address, a phone number, a breakdown of permissions or internal IDs in there and you have published them to everyone who sees the token. Remember while designing that anyone can open browser DevTools and read the contents of their own token. Keep claims minimal and fetch details from the server when you actually need them. There are also many situations where a JWT is simply not the best fit — for an ordinary web application on a single domain, a server-side session is simpler and can log the user out instantly. Where JWT genuinely earns its place is authentication spanning several services, or an architecture where the verifier cannot call back to the issuer. "It is modern" is not a reason — choose it based on whether you can accept the trade-off: statelessness in exchange for the inability to revoke.
📖 How to Use
-
1
Set algorithm and payloadChoose HS256 / HS384 / HS512 and enter your JSON claims in the Payload field. Use the +iat / +exp buttons to add standard claims in one click.
-
2
Enter or generate a secretType a key into the Secret field, or click Random to generate a cryptographically secure 256-bit secret. Select UTF-8, Base64, or Base64URL input format.
-
3
Copy the generated JWTThe signed JWT appears instantly in the right panel. Click Copy to get it on your clipboard, ready for JWT decoder or API testing.
❓ Frequently Asked Questions
What is the difference between HS256, HS384, HS512?
Is it safe to enter a production secret here?
Is RS256 or ES256 (asymmetric) supported?
🐛 Found a bug or issue with this tool?
Free to use, no signup. Even just the steps to reproduce are helpful. Reports go directly to the operator and help us fix issues.
Thanks for your report!
Your report has been delivered to the operator and will be used to improve the tool.