Skip to content

Free JWT Secret Generator — HS256/384/512

Generate a strong, RFC-correct JWT secret for HS256/384/512 — 100% in your browser, never sent to a server. base64url, base64 or hex; copy for .env.

No Tracking Runs in Browser Free
Your secret is generated locally with crypto.getRandomValues and never uploaded, logged, or stored. It stays on this device.
16 64

Equivalent CLI commands

Reviewed for RFC 7518 §3.2 key-length correctness, RFC 4648 encoding accuracy across base64url / base64 / hex, CSPRNG sourcing (crypto.getRandomValues, never Math.random), no-network/no-storage privacy of the generated secret, and accessibility (labelled controls, show/hide masking, screen-reader announcements on generate and copy). — Go Tools Security Tooling Team · Jun 16, 2026

What Is a JWT Secret Generator?

A JWT secret generator produces the random signing key that an HMAC-signed JSON Web Token uses to prove it has not been tampered with. When you sign a token with HS256, HS384, or HS512, the algorithm runs HMAC over the token's header and payload using a single shared secret; the verifier recomputes the same HMAC with the same secret and accepts the token only if the signatures match. The whole security of that scheme rests on the secret being long and unpredictable — which is exactly what this tool creates: a high-entropy random string, generated in your browser, sized correctly for the algorithm you pick.

It is worth being precise about what this tool does and does not do. It generates the secret key — the value you put in your JWT_SECRET environment variable — not a finished token. If you want to assemble a header and payload and sign them into an actual JWT, that is the job of the JWT Encoder; to take an existing token apart and verify its signature, use the JWT Decoder. Think of the secret as the key and the encoder as the lock it operates: you generate the key once, store it safely, and reuse it to sign and verify many tokens.

How long should the key be? The answer is fixed by the spec, not by preference. RFC 7518 §3.2 — the JSON Web Algorithms standard — requires that an HMAC key be at least as large as the hash output: "A key of the same size as the hash output (for instance, 256 bits for HS256) or larger MUST be used." That gives a clean table the generator follows automatically:

| Algorithm | HMAC | Min bytes | Min bits | hex chars | base64 chars | base64url chars | |-----------|------|-----------|----------|-----------|--------------|-----------------| | HS256 | HMAC-SHA-256 | 32 | 256 | 64 | 44 | 43 | | HS384 | HMAC-SHA-384 | 48 | 384 | 96 | 64 | 64 | | HS512 | HMAC-SHA-512 | 64 | 512 | 128 | 88 | 86 |

The character counts come from the RFC 4648 encodings of those byte lengths: hex doubles the byte count; base64 expands by 4⁄3 with padding; base64url drops the padding, so a 32-byte key is 43 base64url characters rather than 44. base64url is JWT's native encoding — URL-safe alphabet, no padding — which is why it is the default output here; a secret in base64url can sit in a header, a URL, or a config value with no escaping.

Randomness is the part you cannot compromise on. This generator draws its bytes from crypto.getRandomValues, the browser's cryptographically secure pseudo-random number generator, the same primitive that backs Web Crypto key generation. It never uses Math.random, which is fast but predictable and completely unsuitable for a signing key — a predictable RNG means a guessable secret, and a guessable secret means forgeable tokens. Because HMAC verification happens locally with the shared secret, an attacker who captures a token can brute-force a weak key offline with no rate limit; tools such as hashcat (mode 16500) and jwt_tool exist precisely to do this. A full-entropy 32-byte random key, on the other hand, is computationally out of reach. The lesson is blunt: never use a password, a dictionary word, or a hand-typed string as a JWT secret — generate a random one.

Finally, generating the key client-side is itself a security property. A signing secret should never be transmitted to a third party, not even the site that helps you create it. Every byte here is produced and encoded in your browser; nothing is uploaded, logged, or stored. When you are ready to ship the key, the Copy for .env button hands you a JWT_SECRET=… line, and if you need it folded into a larger configuration the JSON to .env converter can help. Generate, copy, store it in a secrets manager — and rotate it with a kid header and overlapping validity windows when the time comes.

// The secret you generate here goes straight into your signing code.
// Node.js with jsonwebtoken — the JWT_SECRET env var holds the key.
import jwt from 'jsonwebtoken';

const secret = process.env.JWT_SECRET; // e.g. base64url value from this tool

// Sign a token with HS256 (HMAC-SHA-256).
const token = jwt.sign({ sub: 'user-42', role: 'member' }, secret, {
  algorithm: 'HS256',
  expiresIn: '15m'
});

// Verify it — pin the algorithm to a whitelist; never trust the token's alg.
const payload = jwt.verify(token, secret, { algorithms: ['HS256'] });

// ---------------------------------------------------------------
// Python with PyJWT — same secret, same algorithm pinning.
// import jwt
// token = jwt.encode({"sub": "user-42"}, key, algorithm="HS256")
// payload = jwt.decode(token, key, algorithms=["HS256"])  # whitelist!

// ---------------------------------------------------------------
// Equivalent-strength CLI generation (32 bytes for HS256):
//   openssl rand -base64 32
//   node -e "console.log(require('crypto').randomBytes(32).toString('base64url'))"
//   python -c "import secrets; print(secrets.token_urlsafe(32))"

Key Features

Algorithm-Aware Key Length

Pick HS256, HS384, or HS512 and the generator sets the RFC 7518 §3.2 minimum key size automatically — 32, 48, or 64 bytes. You can request a longer key, but you can never accidentally provision an undersized one that violates the spec or that a strict library will refuse to sign with.

Three Text-Safe Output Formats

Get the same random bytes as base64url (JWT's native, URL-safe, no-padding encoding — the default), standard base64, or hex, shown side by side. base64url is the safest default for a JWT_SECRET; switch formats when a specific loader or library expects another. Entropy is identical across all three.

Cryptographically Secure Randomness

Every secret is drawn from crypto.getRandomValues, the browser's CSPRNG and the primitive behind Web Crypto key generation. Never Math.random. That guarantees a full-entropy key with no predictable structure — the property that puts the secret beyond offline brute-force reach.

Copy for .env in One Click

Copy for .env wraps the value in the conventional JWT_SECRET=… assignment, one line, no quotes — ready to paste into a .env file, a Docker secret, or a CI variable without hand-typing the key name. Plain Copy grabs the raw secret when you need just the value.

Equivalent CLI Commands

A panel prints the matching openssl rand, Node crypto.randomBytes, and Python secrets one-liners for the selected algorithm, so you can reproduce an equal-strength key in a provisioning script or a Dockerfile. Most competing tools omit this; here it is built in.

Show / Hide Masking

The secret is masked by default so it stays off-screen during a demo, a tutorial, or a screen share. Reveal it with the eye icon only when you are ready to copy. Copy actions always place the real secret on the clipboard, whether it is shown or hidden.

100% Private, Browser-Only

The secret is generated, encoded, and displayed entirely on your device. No network requests, no logging, no storage — verify in DevTools → Network. A signing key should never reach a third party, and here it never does, which is the whole reason to generate it client-side.

Available in 15 Languages

The full interface — labels, instructions, and guidance — is localized into 15 languages, so the tool is usable and the security advice is clear no matter where your team works.

Worked Examples

Generate an HS256 secret in base64url (the default)

Algorithm: HS256 · Format: base64url
3sJ9aFq2kP7mWcZ1xL0nVtRbYdGhU8eAoI4QpNlKj0

HS256 signs with HMAC-SHA-256, so RFC 7518 §3.2 requires a key of at least 32 bytes (256 bits). The generator draws 32 cryptographically secure random bytes from crypto.getRandomValues and encodes them as base64url — the no-padding, URL-safe alphabet JWT itself uses. 32 bytes become a 43-character base64url string. Drop the value straight into JWT_SECRET. Each click regenerates a fresh secret; nothing is ever the same twice.

Generate an HS512 secret (64 bytes / 512 bits)

Algorithm: HS512 · Format: base64url
k2Lp9XqA0mNbVcZ7rT4wYsHfGjUe8RoIdPlNkBvM3xQ1aWtCyZuS6FhEgJ (86 chars)

HS512 uses HMAC-SHA-512, whose hash output is 64 bytes, so RFC 7518 §3.2 mandates a key of at least 64 bytes (512 bits). The tool senses the algorithm and raises the byte count automatically — you never have to remember the minimum. 64 random bytes encode to an 86-character base64url string, 88 characters in standard base64, or 128 hex characters. Picking a longer algorithm here is the one-click way to provision a higher-entropy secret.

Copy the secret as a .env line

Click "Copy for .env"
JWT_SECRET=3sJ9aFq2kP7mWcZ1xL0nVtRbYdGhU8eAoI4QpNlKj0

Copy for .env wraps the generated value in the conventional JWT_SECRET=… assignment so you can paste it directly into a .env file, a Docker secret, or a CI variable without hand-typing the key name. The value stays on one line with no surrounding quotes — exactly what dotenv-style loaders expect. Need the variable embedded in a wider config? Pair this with the JSON to .env converter linked below.

Reproduce the secret from a CLI (equivalent strength)

Show the CLI command
openssl rand -base64 32

The CLI panel prints the openssl, Node, and Python commands that draw the same number of secure random bytes for the selected algorithm — openssl rand -base64 32 for HS256, …48 for HS384, …64 for HS512. The output is an equal-strength secret, not a byte-identical string: openssl emits standard base64 with padding while this tool defaults to base64url, so the alphabets and trailing characters differ. Use whichever fits your provisioning script; the entropy is the same.

Show and hide the secret

Toggle the eye icon
•••••••••••••••••••••••••••••••••••••••••••  ↔  3sJ9aFq2kP7m…

The secret is masked by default so it cannot be shoulder-surfed or captured by a screen recording during a demo or screen share. Click the eye icon to reveal it when you are ready to copy, and hide it again afterwards. Copy and Copy for .env work whether the value is shown or masked — the real secret is always what lands on your clipboard, never the dots.

How to Use the JWT Secret Generator

  1. 1

    Choose the signing algorithm

    Select HS256, HS384, or HS512. The generator instantly applies the RFC 7518 §3.2 minimum key length for that HMAC variant — 32, 48, or 64 bytes — so you never have to look the number up or risk an undersized key.

  2. 2

    Pick the output format

    base64url is the default — JWT's native URL-safe, no-padding encoding. Switch to standard base64 if a loader expects it, or hex when a system only accepts 0–f characters. All three encode the same random bytes with identical entropy.

  3. 3

    Reveal and copy the secret

    The secret is masked by default to keep it off-screen during a demo or screen share. Click the eye icon to reveal it, then Copy to grab the raw value or Copy for .env to copy a JWT_SECRET=… line ready for a .env file or CI variable.

  4. 4

    Regenerate as needed

    Click Regenerate for a fresh, independent secret drawn from crypto.getRandomValues. Generate one per environment — never reuse the same signing key across development, staging, and production.

  5. 5

    Use the CLI equivalent or move on to signing

    The CLI panel shows the matching openssl, Node, and Python one-liners for scripted provisioning. With your secret in hand, sign a token with the JWT Encoder and confirm the signature with the JWT Decoder.

Common JWT Secret Mistakes

Used a password or short phrase as the secret

A human-chosen string has far too little entropy for a signing key and can be recovered offline with a dictionary or brute-force attack, after which any token can be forged. Generate a full-entropy random secret instead.

✗ Wrong
JWT_SECRET=mySuperSecret123  →  low entropy, brute-forceable
✓ Correct
JWT_SECRET=3sJ9aFq2kP7mWcZ1xL0nVtRbYdGhU8eAoI4QpNlKj0  →  32 random bytes

Key shorter than the algorithm requires

RFC 7518 §3.2 mandates an HMAC key at least as long as the hash output. A 16-byte key for HS256 is below the 32-byte floor — it weakens the signature and some libraries reject it outright.

✗ Wrong
16-byte key with HS256  →  below the 32-byte minimum
✓ Correct
32-byte key with HS256  →  meets RFC 7518 §3.2

Generated the key with Math.random

Math.random is not cryptographically secure — its output is predictable, so a secret built from it is guessable and the tokens it signs are forgeable. A signing key must come from a CSPRNG like crypto.getRandomValues.

✗ Wrong
Math.random()-based key  →  predictable, unsafe
✓ Correct
crypto.getRandomValues key  →  full entropy

Re-encoded the secret before signing

Store and feed the exact string the tool produced. Base64-decoding it to bytes in one service but treating it as a literal string in another gives the two sides different keys, and every signature check fails.

✗ Wrong
Service A: raw string · Service B: base64-decoded  →  signatures never match
✓ Correct
Both services use the identical stored string  →  signatures verify

Reused the same secret across all environments

One JWT_SECRET shared by dev, staging, and production means a leak anywhere forges tokens everywhere and rotation becomes all-or-nothing. Provision a distinct secret per environment.

✗ Wrong
Same JWT_SECRET in dev, staging, prod  →  one leak breaks all
✓ Correct
A unique secret per environment  →  blast radius contained

Trusted the token's alg on verification

Letting the verifier accept whatever algorithm the token declares enables alg:none and HS/RS confusion forgeries. Pass an explicit algorithm whitelist no matter how strong the secret is.

✗ Wrong
jwt.verify(token, secret)  →  accepts the token's alg
✓ Correct
jwt.verify(token, secret, { algorithms: ['HS256'] })  →  pinned

Who Uses This Tool

Provision a JWT_SECRET for a New Service
Spinning up an API that issues HMAC-signed tokens? Pick the algorithm your library uses, copy the secret as a JWT_SECRET=… line, and drop it into the service's environment. Generate a distinct key for development, staging, and production — never share one secret across environments.
Rotate a Compromised or Aging Secret
When a key is suspected leaked or simply due for rotation, generate a fresh secret here, assign it a new kid, and roll it out with an overlap window so live tokens keep verifying until they expire. In a confirmed compromise, rotate immediately and drop the old key from the accepted set.
Replace a Weak or Hand-Typed Key
Inherited a codebase whose JWT_SECRET is a short phrase or a copied example value? That key is brute-forceable offline. Generate a full-entropy 32-byte replacement, swap it in behind a rotation window, and close the token-forgery hole before it is exploited.
Script Key Generation in a Pipeline
Need the key created in CI or a Dockerfile rather than by hand? Use the CLI panel's openssl, Node, or Python one-liner to mint an equal-strength secret inside your provisioning script, and use this page to understand the byte lengths and encodings each command produces.
Teach JWT Signing Safely
Walk a team through how HS256 works without ever exposing a real production key — generate a throwaway secret on screen (masked until you reveal it), sign a sample token with the JWT Encoder, and verify it with the JWT Decoder so the whole sign-and-verify loop is visible.
Compare HS256, HS384, and HS512 Key Sizes
Deciding which HMAC variant to standardize on? Flip between the algorithms to see how the required key length and encoded string grow — 43, 64, and 86 base64url characters — and pick the strength-versus-token-size trade-off that fits your system before you commit it to config.
Generate Keys for Local Development
Need a quick, valid secret to get a local auth flow running? Generate one in a click, copy it for .env, and you are unblocked — with a real CSPRNG key rather than a placeholder you will forget to replace before deploy.

How the Generator Works

crypto.getRandomValues (CSPRNG)
Secrets are generated by filling a Uint8Array with crypto.getRandomValues, the Web Crypto cryptographically secure pseudo-random number generator. It is the same entropy source that backs Web Crypto key generation. Math.random is never used anywhere — it is statistically predictable and unfit for any cryptographic key.
RFC 7518 §3.2 Key Sizing
The byte count per algorithm follows the JSON Web Algorithms requirement that an HMAC key be at least the size of the hash output: 32 bytes for HS256 (SHA-256), 48 for HS384 (SHA-384), 64 for HS512 (SHA-512). Selecting the algorithm sets the minimum; the generator will not emit a key below the spec floor.
RFC 4648 Encodings (base64url / base64 / hex)
The raw bytes are encoded with the RFC 4648 alphabets. base64url uses the URL-safe alphabet without padding (32 bytes → 43 chars), standard base64 uses +, /, and = padding (→ 44 chars), and hex writes two characters per byte (→ 64 chars). Switching formats re-encodes the same bytes — the underlying entropy is unchanged.
Why base64url Is the Default
JWT components are themselves base64url-encoded, and the URL-safe, no-padding alphabet means a secret in base64url never needs escaping in a header, a URL, or a config file. Standard base64's + and / and trailing = can break in those contexts, so base64url is the conservative default for a JWT_SECRET.
Copy-for-.env Formatting
Copy for .env emits JWT_SECRET= on a single line with no surrounding quotes — the shape dotenv-style loaders parse without modification. The raw secret never includes characters that would require quoting in a .env file, so the line is safe to paste as-is.
Equivalent-Strength CLI Commands, Not Byte-Identical
The CLI panel's openssl rand -base64 N, Node randomBytes(N).toString('base64url'), and Python secrets.token_urlsafe(N) commands all draw N secure random bytes for the chosen algorithm. They produce equal-strength keys, not the same string — openssl emits padded standard base64, so the alphabet and trailing characters differ from this tool's base64url default.

JWT Secret Best Practices

Match the Key Length to the Algorithm
Use at least 32 bytes for HS256, 48 for HS384, and 64 for HS512, as RFC 7518 §3.2 requires. This generator does it for you, but if you size a key by hand, never go below the hash output length — an undersized HMAC key both weakens the signature and may be rejected by strict libraries.
Always Generate with a CSPRNG, Never a Password
A JWT secret is a machine credential nobody needs to memorize, so spend the full entropy: use a cryptographically secure random key, not a passphrase, a dictionary word, or a hand-typed string. Human-chosen secrets are the easiest target for the offline brute-force attacks that JWT cracking tools automate.
Use a Unique Secret per Environment
Development, staging, and production should each have their own JWT_SECRET. Sharing one key means a leak in a low-stakes environment forges tokens everywhere, and it makes rotation all-or-nothing. Generate a separate secret here for each environment and store each in its own secrets manager scope.
Pin the Algorithm When You Verify
On the verifying side, always pass an explicit algorithm whitelist — algorithms: ['HS256'] in jsonwebtoken, algorithms=["HS256"] in PyJWT — and never trust the alg field inside the token. Accepting the token's self-declared algorithm enables the classic alg-confusion and alg:none forgery attacks, regardless of how strong your secret is.
Rotate with a kid Header and Overlapping Keys
Tag signed tokens with a key identifier (kid) and publish active keys via a JWKS endpoint so you can rotate without downtime: sign new tokens with the new key while still accepting the old one until its tokens expire. On a suspected compromise, skip the overlap and revoke the old key immediately.

Frequently Asked Questions

Is my generated JWT secret sent to your server?
No. The secret is generated entirely in your browser with crypto.getRandomValues, the platform's cryptographically secure random number generator. The bytes are produced on your device, encoded locally, and shown only to you. Nothing is uploaded, nothing is logged, nothing is written to disk, and nothing is sent to any third party — open DevTools → Network and you will see zero requests fire when you click Regenerate or Copy. That means a key you generate here is yours alone the instant it appears; no server ever observes it. This is the whole point of generating a signing secret client-side rather than on a website that could, in principle, keep a copy of every key it hands out.
How do I generate a secure JWT secret?
Three steps. First, pick the signing algorithm your application uses — HS256, HS384, or HS512 — and the generator immediately sizes the key to the RFC 7518 §3.2 minimum for that variant (32, 48, or 64 bytes), so you never hand-pick a number or risk an undersized key. Second, leave the encoding on base64url (JWT's native, URL-safe format) or switch to base64 or hex if your config loader expects one of those. Third, click Copy — or Copy for .env to get a ready-to-paste JWT_SECRET=… line — and store the value in a secrets manager or environment variable, never in source control. Because every byte comes from crypto.getRandomValues, a 32-byte key already carries 256 bits of entropy, which is far beyond the reach of the offline brute-force attacks that break human-chosen secrets. Prefer the command line? The tool also prints equivalent openssl, Node, and Python one-liners you can paste into a terminal.
How long should an HS256 JWT secret be?
At least 32 bytes (256 bits). RFC 7518 §3.2 — the JSON Web Algorithms spec — states that for HMAC signatures "a key of the same size as the hash output (for instance, 256 bits for HS256) or larger MUST be used." HS256 signs with HMAC-SHA-256 (256-bit hash), so the minimum key is 32 bytes; HS384 uses HMAC-SHA-384 and needs at least 48 bytes (384 bits); HS512 uses HMAC-SHA-512 and needs at least 64 bytes (512 bits). This generator picks the correct minimum automatically when you choose the algorithm, and you can request a longer key. A shorter key is not just weaker — it violates the spec and some libraries will refuse to sign with it.
What is the difference between base64url, base64, and hex, and which should I pick?
All three encode the same random bytes; they differ only in the character alphabet, not in entropy. base64url is JWT's native encoding — it uses a URL-safe alphabet (- and _ instead of + and /) and omits padding, so it never needs escaping in a token, a URL, or a header. That is why it is the default here. Standard base64 uses +, /, and = padding; choose it when a config loader or library specifically expects classic base64. hex (base16) writes each byte as two characters 0–f, producing a longer but unambiguous string that is handy when a system rejects non-alphanumeric characters. For a JWT_SECRET environment variable, base64url is the safest default; any of the three works as long as you store the exact string and feed it back to your signing library unchanged.
Can a weak JWT secret be cracked?
Yes — and this is the single biggest risk with HMAC-signed JWTs. Because HS256/384/512 use one shared secret, anyone who holds a token can run an offline brute-force or dictionary attack against the signature with no rate limit and no server contact. Tools like hashcat (mode 16500 targets JWT) and jwt_tool are purpose-built for this; on commodity GPUs a low-entropy secret can typically fall in seconds to hours, and a dictionary word or a leaked password can fall almost immediately. A full-entropy 32-byte random key from this generator is far beyond the reach of brute force. Once an attacker recovers the secret they can forge any token — including one that claims admin privileges — so secret strength is not optional. Generate the signing key with a CSPRNG, never a human-chosen string. For a deeper treatment of weak-secret, alg-confusion, and token-replay attacks, see our guide to JWT security best practices.
Can I use a password as my JWT secret?
You can, but you should not. A human-memorable password — even a long passphrase — carries far less entropy than 32 random bytes, which makes it a realistic target for the offline brute-force and dictionary attacks described above. JWT secrets are machine-to-machine credentials; nobody needs to memorize them, so there is no reason to trade entropy for memorability. Generate a random secret here, store it in a secrets manager or an environment variable, and let your application read it. If you need memorable credentials for a different purpose, that is a job for a Password Generator or, for storing user passwords, a one-way hash from the bcrypt Generator — not for a token-signing key.
How do I rotate a JWT secret without breaking live tokens?
Rotate with overlap rather than a hard cutover. Add a key identifier (the kid header) to the tokens you sign so a verifier knows which secret to check against, and publish your active keys — typically through a JWKS endpoint your services read. To rotate: generate a new secret here, start signing new tokens with the new kid while still accepting the previous key for verification, and only retire the old key after every token signed with it has expired. That overlap window means no valid session is invalidated mid-flight. In a suspected compromise, skip the graceful overlap: rotate immediately, drop the old key from the accepted set, and force re-authentication so leaked tokens stop verifying at once.
How is an HMAC (HS*) key different from an RSA or ECDSA (RS*/ES*) key?
They solve the same problem with opposite key models. HS256/384/512 are HMAC algorithms: they use one symmetric secret — the kind this tool generates — that both signs and verifies, so every party that can verify a token can also forge one. That is simple and fast and ideal when a single service both issues and checks its own tokens. RS* (RSA) and ES* (ECDSA) are asymmetric: they use a key pair, where a private key signs and a separate public key only verifies. You hand the public key to anyone who needs to validate tokens without ever exposing the signing key — the right choice when an identity provider issues tokens that many independent services verify. This generator produces HMAC symmetric secrets only. To assemble and sign an actual token with the key you generate, use the JWT Encoder; to inspect and verify one, use the JWT Decoder.

Related Tools

View all tools →