JWT Secret & Webhook Secret Generator

Generate long random secrets for JWT signing, webhook validation, session cookies, and internal services.

Private by design: generation runs in your browser with Web Crypto randomness. Secrets are not sent to StashGrid.

How to choose a JWT signing secret

A JWT signing secret is not a password. Nobody types it, nobody remembers it, and it is never checked against a database. It is the key to an HMAC — the shared value your server uses to stamp a token and, later, to prove that the token came back unmodified. Everything about how you pick one follows from that.

When your token header says HS256, the signature is HMAC-SHA-256 over the header and payload. Anyone who holds that secret can mint a token claiming to be any user on your system, including an administrator. There is no second check. The secret is the whole security boundary, which is why it should be random bytes from a cryptographic source rather than anything a person invented.

How many bytes you actually need

RFC 7518, the JSON Web Algorithms spec, requires that an HMAC key be at least as long as the hash output. That sets the floor:

This page defaults to 64 bytes because it satisfies every one of those algorithms, costs nothing extra, and means you never have to revisit the decision if you later move from HS256 to HS512. Going beyond 64 bytes buys no additional security: HMAC folds keys longer than the hash block size back down by hashing them first.

To put 32 bytes in perspective — a randomly generated 12-character password drawn from all 94 printable ASCII characters carries about 79 bits of entropy. A 32-byte secret carries 256. The gap is not a matter of degree; one is guessable by a determined attacker with a GPU and the other is not guessable at all.

Base64url or hex — it makes no difference to strength

The format selector on this page changes how the same random bytes are written down, not how many there are. Sixty-four random bytes are 512 bits of entropy whether you encode them as base64url or as hex. What changes is the length of the string you paste into your configuration:

Choose base64url when you want the shorter string and your config format is happy with - and _. Choose hex when something downstream is fussy about non-alphanumeric characters, or when you want a value that is trivially safe to paste into a shell, a URL, or a YAML file without quoting surprises. Base64url is used here rather than standard base64 precisely because it omits +, / and =, the three characters most likely to be mangled in transit.

Why a memorable passphrase is a real vulnerability

Weak HMAC secrets are not a theoretical problem. Offline cracking of HS256 tokens is a standard, well-tooled attack: an attacker who captures a single valid JWT can test candidate secrets against it as fast as their hardware allows, with no network traffic and nothing to rate-limit. Dictionary words, project names, secret, changeme, and the default values shipped in framework tutorials all fall in seconds.

The signature in a JWT is public — it travels in the token. That is what makes this attack possible, and it is why the only defense is a key large and random enough that guessing is hopeless.

When a shared secret is the wrong choice entirely

HMAC signing assumes that every party who needs to verify a token is also trusted to create one, because verification and creation use the same key. That is fine for a single application signing its own sessions. It stops being fine the moment you have several services, a mobile client, or a third party that needs to check tokens but must never be able to issue them.

In those cases use an asymmetric algorithm — RS256 or ES256 — where the issuer holds a private key and everyone else verifies with a public key that grants no signing power. A shared secret distributed to six services is really six chances of a leak, and any one of them can impersonate your auth server.

A strong secret does not fix a weak verifier

Two classic JWT flaws are unaffected by how good your secret is, and both are worth checking in your own code:

Rotating without logging everyone out

Rotating a signing secret invalidates every token signed with the old one, which in practice means every user is logged out at once. To avoid that, run two secrets briefly: sign new tokens with the new secret while accepting either during verification, wait for your longest token lifetime to elapse, then drop the old secret. A kid (key ID) in the token header makes this straightforward, because the verifier can tell which key to use rather than trying both.

Rotate on a schedule you can actually keep, and rotate immediately if a secret is ever committed to a repository, pasted into a ticket, or printed in a log.

Webhook signing secrets

The same generator suits webhook secrets, which solve a related problem: proving that an inbound HTTP request came from the sender it claims. The sender computes an HMAC of the raw request body using the shared secret and puts it in a header; you recompute it and compare.

Three details matter more than secret length here. Hash the raw body, before any JSON parsing, because re-serializing changes bytes and breaks the signature. Compare with a constant-time function rather than ==, so that the comparison itself does not leak the correct value one byte at a time. And reject requests whose signed timestamp is older than a few minutes, otherwise a captured request stays replayable forever.

Where the secret should live

Not in your source code, and not in a file that your repository tracks. Put it in an environment variable loaded from a secret manager, a Kubernetes secret, or your platform's configuration store, and give each environment its own value. A development secret that also works in production means a laptop compromise is a production compromise.

If a secret does end up somewhere it should not be, treat it as burned and rotate it. Deleting a commit does not delete it from every clone, cache, and CI log that has already seen it.

Related password tools

FAQ

How long should a JWT secret be?

At least as long as the hash output of the algorithm you sign with: 32 bytes for HS256, 48 for HS384, 64 for HS512. RFC 7518 makes this a requirement, not a suggestion. Sixty-four bytes is a sensible default because it satisfies all three and costs nothing extra.

Does a longer secret make the signature harder to break?

Only up to a point. HMAC hashes any key longer than the hash block size back down before using it, so a 200-byte secret gives you no more real security than a 64-byte one. Past 64 bytes you are adding string length, not strength.

Is base64url stronger than hex?

No. Both encode the same random bytes; only the written length differs. Thirty-two bytes is 43 base64url characters or 64 hex characters, and either way it is 256 bits of entropy. Pick whichever your configuration format handles most cleanly.

Can I use a memorable passphrase instead?

No. The signature travels inside the token, so an attacker who captures one valid JWT can test candidate secrets offline at full hardware speed with nothing to rate-limit them. Dictionary words and tutorial defaults fall in seconds. This is a routine attack, not a hypothetical one.

Can I reuse one secret everywhere?

No. Use a different secret for each application and each environment. Anyone holding an HS256 secret can mint a token for any user, so one shared value across dev, staging and production means a laptop compromise is a production compromise.

When should I use RS256 instead of a shared secret?

As soon as something needs to verify tokens without being trusted to issue them — multiple services, a mobile client, or a third-party integration. HMAC uses the same key for both operations, so every verifier is also a potential forger. RS256 and ES256 split those roles with a private signing key and a public verification key.

How do I rotate the secret without logging everyone out?

Accept two secrets at once. Sign new tokens with the new secret while verification tries either, wait for your longest token lifetime to pass, then retire the old one. A kid header makes this cleaner by telling the verifier which key to use.

Does a strong secret protect me from the "alg: none" attack?

No. If your verification code reads the algorithm out of the incoming token and trusts it, an attacker can set it to none and skip signing entirely — the key is never consulted. Pin the expected algorithm explicitly when you verify. The same applies to algorithm confusion, where an RS256 public key is used as an HS256 secret.

Can I use this for webhook signing secrets?

Yes, that is the same kind of value. When you verify the incoming signature, hash the raw request body before parsing, compare using a constant-time function rather than ==, and reject signed timestamps older than a few minutes so captured requests cannot be replayed indefinitely.

Is the secret generated here sent anywhere?

No. It is produced in your browser by the Web Crypto API's getRandomValues, the same cryptographic source your operating system uses. Nothing is transmitted to StashGrid and nothing is stored. That said, for a production secret it is reasonable practice to generate it on the machine that will use it — openssl rand -base64 64 does the same job at a shell.