JWT Generator
Build a JSON Web Token and sign it with your own secret β with iat and exp handled correctly, and the signature re-verified before the token is shown to you.
The secret never leaves this page. Signing happens in your browser, and the key is not sent anywhere, saved, or included in anything you copy. Only HS256/384/512 are offered β RS and ES signing would need your private key, and pasting a production private key into any web form is a bad idea however carefully the page is written.
alg automatically β a token whose
header disagrees with how it was signed is rejected by every verifier.
exp is valid forever, which is the single
most common JWT mistake.
{{ weakKeyNote }}
{{ headerError }}
{{ payloadError }}
{{ injectedClaims.join(' and ') }} will be added automatically when you sign.
{{ error }}
Signed and verified
The signature was recomputed from the emitted token and matched, so this is a well-formed {{ algo }} token β {{ parts.bytes }} bytes. Issued {{ parts.issuedAt }}. Expires {{ parts.expiresAt }}.
{{ token }}
Three Base64URL segments joined by dots: header, payload, signature. The first two are not encrypted β anyone holding this token can read them.
Paste this into the JWT Decoder with the same secret to confirm it verifies there too β both tools use the same HMAC implementation, so they cannot disagree.
The token is built and signed entirely in your browser. Your signing secret and payload are never uploaded to a server.
What signing a JWT actually does
A JWT is three Base64URL segments joined by dots. The first two β header and payload β are encoding, not encryption: anyone with the token can read every claim in it. What the signature adds is proof that the token was produced by someone holding the secret and has not been altered since. If you need the contents hidden rather than merely tamper-evident, a signed JWT is the wrong tool.
Never put a secret in the payload
It follows directly from the above, and it is worth stating because it happens constantly. Passwords, API keys and internal identifiers in a JWT payload are readable by anyone the token passes through, including the browser it is stored in.
exp, iat, and the seconds-versus-milliseconds trap
Both are Unix timestamps in seconds. JavaScript's Date.now() returns
milliseconds, so passing it straight through produces a token that expires roughly 50,000 years
from now β a bug that silently disables expiry entirely. This tool divides correctly and shows
you the resulting ISO dates so you can check.
Your secret's encoding matters
The same mistake the HMAC Generator warns about: webhook and auth providers commonly publish signing secrets as hex or Base64 strings. Signing with those characters treated as literal text keys with entirely different bytes, and every verifier will reject the result with nothing to explain why. Set Secret as to match the form your secret was given in.
Checking the token you just made
Signing here and verifying in the JWT Decoder uses one shared HMAC implementation, so the two can never disagree about what a signature should be. That is a property of sharing the primitive rather than reimplementing it.
Frequently asked questions
Is a signed JWT encrypted?
No, and this is the most consequential misunderstanding about JWTs. The header and payload are Base64URL β encoding, not encryption β so anyone holding the token can read every claim in it without any key. The signature only proves the token came from someone with the secret and has not been altered. Never put a password, API key or anything else sensitive in the payload.
Why does it only offer HS256, HS384 and HS512?
Those sign with a single shared secret, which is something a browser-only tool can do safely. RS, PS and ES tokens sign with a private key, and a page asking you to paste a production private key into a web form is a bad idea however carefully the crypto is written β so it is deliberately absent rather than half-supported.
What do iat and exp do, and why does the tool add them?
They are Unix timestamps in seconds: iat records when the token was issued and exp when it stops being valid. A token with no exp never expires, which is the single most common JWT mistake, so both are offered as one-click options with the expiry shown as a readable date to check against.
My token is rejected by the server. What is wrong?
Most often the secret's encoding. Providers frequently publish signing secrets as hex or Base64, and signing with those characters treated as literal text uses entirely different key bytes β producing a token that is well-formed but verifies against nothing. Set "Secret as" to match the form you were given. After that, check the alg in the header matches what the server expects.
How short is too short for a secret?
Shorter than the hash output weakens the signature relative to its name: HS256 has a 256-bit output, so a key under 32 bytes gives less strength than the label implies. The tool warns when that happens. Use a long random secret β the Password Generator can make one.
Is my secret uploaded anywhere?
No. Signing runs in your browser using this site's own HMAC implementation. The secret is not transmitted, not written to storage, and not included in anything you copy β and it is masked on screen so it does not linger in a screenshot.