JWT Generator
Sign a JWT with HS256, HS384 or HS512 and custom claims, generate a strong signing secret, and see which claims a validator will object to.
Claims
RFC 7519 registered claimsSigning
Enter a secret, or generate one. 32 bytes is what RFC 7518 asks for with HS256.
Payload
{}Token
Enter a signing secret to produce a token.
Signing happens in your browser with WebCrypto. The secret is never transmitted and never leaves this page — but treat any token you paste into a browser tool, including this one, as one you would not use in production.
About the JWT Generator
Build a JWT with the claims you need, sign it with HS256, HS384 or HS512, and get a token you can paste into a request while you are testing an API. Signing uses WebCrypto in your browser, so the secret never travels anywhere — which is the only defensible way for a web page to offer this at all.
The registered claims of RFC 7519 have their own fields, because they are the ones a validator actually checks: `iss`, `sub`, `aud`, `exp`, `nbf`, `iat` and `jti`. Expiry is entered as a duration and converted to the absolute epoch second the standard requires. Anything else you need goes in the custom claims box and is merged over the registered ones, so an intentional override is possible but never accidental.
There is also a secret generator, because that is the other half of the job and the half that is usually done badly. RFC 7518 requires an HMAC key at least as long as the hash output — 32 bytes for HS256 — and a token signed with a memorable passphrase can be cracked offline at billions of guesses per second, using nothing but the token itself. The strength readout tells you where your secret sits against that bar.
- HS256, HS384 and HS512 signing via WebCrypto — nothing is transmitted
- Registered claims as fields, with expiry entered as a duration
- Custom claims as JSON, merged over the registered ones
- Cryptographically random secret generation in hex, base64 or base64url
- Entropy estimate for whatever secret you type, judged against RFC 7518
- Warnings for the payloads a resource server will reject, or should
How to use it
- Fill in the claims you need. Leave a field empty to omit that claim entirely.
- Add any application-specific claims as a JSON object in the custom claims box.
- Enter your signing secret, or press Generate for a random one of the right length. Turn on "secret is base64" if your service stores it that way — Auth0 and several others do.
- Copy the token from the bottom panel.
- Read the warnings underneath. They are the things a validator will complain about, or should.
Real-world use cases
Backend & API developers
Mint a token with the exact claims your middleware expects while building or debugging an auth flow, without standing up the real identity provider just to get one test token.
Frontend developers
Generate a token with a specific role or permission claim to test how the UI behaves for different user types, without needing a matching real account for each one.
QA & test engineers
Produce expired, not-yet-valid or malformed tokens on demand to test how the application actually handles each case, rather than waiting for a real token to expire in real time.
API integrators
Build a signed token by hand while integration-testing against a partner's API during onboarding, before your own service's token-issuing code exists yet.
Security & AppSec engineers
Construct tokens with edge-case claims — a missing aud, an oversized payload — to verify a validator rejects what it should, using the warnings panel as a checklist.
Examples
A typical access token
iss: https://issuer.example.com
sub: usr_8f2b
aud: https://api.example.com
exp: 1 hour
custom: { "role": "admin" }{
"iss": "https://issuer.example.com",
"sub": "usr_8f2b",
"aud": "https://api.example.com",
"iat": 1785110400,
"exp": 1785114000,
"role": "admin"
}`exp` and `iat` are seconds since the Unix epoch, not milliseconds — a JavaScript `Date.now()` pasted straight in is off by a factor of a thousand and produces a token valid for 50,000 years.
The three parts of the token
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxIn0.<signature>
header {"alg":"HS256","typ":"JWT"}
payload {"sub":"1"}
signature HMAC-SHA256(header + "." + payload, secret)The first two segments are base64url-encoded JSON. Anyone holding the token can read them without the secret — base64 is encoding, not encryption.
A generated secret
HS256 → Generate 32-byte secret
qX8mB2xNr5vKz1pT7wYc0hLdF4aJeR6sUgO3nQi9M8k
32 random bytes in base64url. Turn on "secret is base64" so the same 32 bytes are used as the key rather than the 43 characters of text.
Verifying what you made
Paste the token and the same secret into the JWT decoder
Signature valid
Worth doing once with your real service's secret: if the decoder says invalid, the usual cause is a base64 secret being used as plain text or the reverse.
Common errors
| Message | Cause | Fix |
|---|---|---|
| invalid signature (from your own service) | The key bytes differ. A base64 secret used as UTF-8 text, or the reverse, gives a completely different key. | Match the toggle to how your service stores the secret. Auth0 signs with the base64-decoded value of the key it shows you; most other stacks use the string as-is. |
| token is expired | `exp` is in the past — often because the machine that issued it and the one validating it disagree about the time. | Most libraries allow a few seconds of clock skew. If your expiry is very short, that skew is the whole budget. |
| The secret is not valid base64 | The base64 toggle is on for a secret that is plain text — a `-`, `_` or space is enough to make it undecodable. | Turn the toggle off, or generate a secret in base64url form. |
| alg none is not offered | Deliberate. `alg: none` produces an unsigned token, and accepting one is CVE-2015-9235 — the algorithm-confusion bug that affected most JWT libraries at once. | There is no legitimate use for it in a tool like this. If you are testing whether your validator rejects it, construct it by hand. |
| RS256 and ES256 are not offered | They need a private key, and pasting a private key into a web page is not something to normalise, whatever the page promises. | Use your language's library — `jsonwebtoken`, `PyJWT`, `jose`. The decoder page refuses asymmetric verification for the same reason. |
| Header too large / 431 | A payload stuffed with permissions or profile data. Tokens travel in the Authorization header, and servers commonly cap headers around 8 KB. | Put an identifier in the token and look the rest up. A JWT is a claim about identity, not a session store. |
Frequently asked questions
›Does my secret leave the browser?
No. Signing runs through WebCrypto in the page, and there is no server component to send it to — the whole site is static. That said, treat any token or secret you paste into any browser tool as one you would not use in production, this page included. Generate throwaway secrets for testing.
›How long should an HMAC secret be?
RFC 7518 requires a key at least as long as the hash output: 32 bytes for HS256, 48 for HS384, 64 for HS512. The reason is specific to JWTs — an attacker with a token has an offline oracle and can test guesses as fast as hardware allows, so a memorable passphrase is not merely weak, it is testable at billions of attempts per second.
›Can anyone read my token's payload?
Yes. The header and payload are base64url-encoded JSON, and base64 is encoding rather than encryption. The signature proves the token was not altered; it hides nothing. Never put a password, a card number or anything else sensitive in a JWT payload — if it must be secret, use JWE or keep it server-side.
›Why does the tool warn about a token with no expiry?
Because a JWT cannot be revoked. Once signed it is valid until it expires, and nothing you do at the issuer takes it back — a token that never expires is a permanent credential for anyone who obtains it. Short-lived access tokens plus a refresh token exist precisely to bound that window.
›What is `jti` for?
A unique identifier for the token, which lets a resource server keep a deny-list of tokens it has seen or revoked. It is the standard partial answer to the fact that JWTs cannot otherwise be revoked, and it is only useful if something is actually recording those identifiers.
›Are `iss` and `aud` worth setting?
Yes, and most validators check them. Without `aud`, a token minted for one service is a valid token at any other service that trusts the same key — an easy privilege escalation in a microservice estate sharing one secret. `iss` is what lets a validator pick which key to check the signature against.
›Is a token generated here safe to use in a real application?
For local development and testing against your own services, yes — as long as the secret is one you generated for that purpose and would not mind rotating. For anything a real user's session depends on, tokens should be minted server-side by your actual auth flow, where the signing key never leaves your infrastructure. Treat this generator the way you would treat a REPL: excellent for building and testing, not a replacement for the production issuer.
›Can I generate an RS256 or ES256 token here?
No — only the HS family (HS256/384/512), which use a single shared secret. RS256 and ES256 are asymmetric and need a private key; generating one client-side and pasting it into a browser page is not something worth normalising, even for testing. Use your language's JWT library for asymmetric signing.
Last updated