JWT Secret Generator
Last updated: 15 August 2026
Reviewed by Gavin ยท Research and drafting assisted by AI
JWT Secret Generator
A JWT secret generator produces cryptographically secure random bytes for signing JSON Web Tokens (JWTs) using the HS256, HS384, and HS512 algorithms. The generator fills a buffer with values from the platform CSPRNG (crypto.getRandomValues() in the browser), encodes those bytes in Hex, Base64, or Base64URL, and exposes the result as a copy-pasteable string ready for an environment variable or secrets manager.
JWT signing secrets are the single root of trust for any HMAC-based JWT deployment. If the secret leaks, an attacker can mint tokens that pass signature verification for every user, so the secret must be high-entropy, never hard-coded, and rotated on a known schedule. This tool makes generating fresh secrets in the right encoding a one-click operation, and it does the work entirely in your browser, no network call, no analytics, no upload.
What is a JWT signing secret?
A JSON Web Token (JWT) is a compact, URL-safe token format defined by RFC 7519. It carries three Base64URL-encoded parts joined by dots: a header describing the algorithm and type, a payload of claims (the data the issuer wants to assert about a subject), and a signature that lets any holder verify the token was minted by a party in possession of the signing material.
The alg field of the header selects how that signature is computed. For the HS family, HS256, HS384, and HS512, the signing material is a single shared secret held by every party that needs to mint or verify tokens. The signature is the HMAC of the dot-joined header and payload, using SHA-256, SHA-384, or SHA-512 respectively. Anyone with the secret can both issue and verify tokens, so the secret is the single root of trust for the entire deployment.
For the RS, PS, ES, and Ed families the signing material is a private/public key pair: the issuer holds the private key and signs with it, while verifiers only need the public half. Those deployments need a real asymmetric key generator (OpenSSL, an HSM, or a KMS), not this tool.
How to use this tool
- Pick a byte length: 16, 24, 32, 64, or 128 bytes. Each byte adds 8 bits of entropy, so a 32-byte secret carries 256 bits.
- Pick an encoding: Base64URL (JWT-safe), Base64, or Hex.
- Read the live entropy counter and strength label, โฅ 256 bits is rated "Very strong" and is the modern floor for HS256.
- Click Generate again to refresh the batch of four secrets.
- Click Copy next to the secret you want; paste it into your
JWT_SECRETenvironment variable, your secrets manager, or your KMS-encrypted secret store. - Treat the copied value as you would any production credential: do not paste it into chat, screenshots, source control, or unsecured files.
Encoding reference
| Encoding | Output length for N bytes | Where it fits |
|---|---|---|
| Hex | 2 ร N characters | Env vars, configs, OpenSSL-style keys, debug logs |
| Base64 | ceil(4 ร N / 3) characters, padded with = | Email-safe transport, generic binary-to-text, MIME |
| Base64URL | ceil(4 ร N / 3) characters, padding stripped, +// replaced by -/_ | JWT (RFC 7519), URL-safe tokens |
Worked example: 32 random bytes encode as exactly 64 hex characters, 44 Base64 characters (with one trailing =), or 43 Base64URL characters (no padding). Entropy is identical regardless of encoding, encoding is purely a presentation choice.
Why three encodings? Hex is the most readable and easy to scan for transcription errors. Base64 is the canonical binary-to-text format for MIME and PEM. Base64URL uses -/_ instead of +// and strips = padding so the string can sit inside a URL path or HTTP header without escaping. If you paste a secret into a JWT library's HS256 configuration field, Base64URL is the safest choice.
Where JWT secrets show up
HS256 / HS384 / HS512 (HMAC-based, shared secret). These algorithms sign and verify the JWT with the same shared secret. Anyone who learns the secret can mint valid tokens, so the secret must stay server-side and have at least as many bits of entropy as the hash output (256 for HS256, 384 for HS384, 512 for HS512). The OWASP JWT cheat sheet calls out this minimum, and HS256 is by far the most common choice because it is simple, fast, and supported by every JWT library.
RS256 / PS256 / ES256 / EdDSA (asymmetric, key pair). These algorithms do not use a shared secret, the issuer signs with a private key and verifiers use the corresponding public key. The random-bytes tool here is still useful for generating the private key seed or for symmetric-coexistence scenarios (for example, deriving a per-tenant HMAC key from a master secret), but production asymmetric deployments normally use a dedicated KMS or library such as openssl genpkey, ssh-keygen, or a managed HSM that gives you a real RSA, ECDSA, or Ed25519 key pair.
Session cookies, OAuth client secrets, webhook signing keys. The same byte-pump pattern applies to any 256+ bit server-side secret. Treat every output of this tool as production-grade credentials: a leaked JWT signing secret compromises every user, a leaked webhook secret compromises every integration, and a leaked cookie-signing secret lets an attacker forge arbitrary sessions.
Refresh tokens, CSRF tokens, API keys. For refresh tokens and CSRF tokens the secret is the token itself (or an HMAC of it). For API keys issued to external customers, the secret string is what they paste into their HTTP client, same rule: 256+ random bits.
Worked examples
1. Generating a 32-byte HS256 secret for a Node.js service. Choose 32 bytes, choose Base64URL, click Generate, copy the secret, and set process.env.JWT_SECRET to that value. In your application code, sign with jsonwebtoken:
import jwt from 'jsonwebtoken';
const token = jwt.sign({ sub: userId }, process.env.JWT_SECRET, {
algorithm: 'HS256',
expiresIn: '15m',
});
2. Rotating from an old to a new secret. Generate a new 32-byte Base64URL secret. Deploy it as the active signer while keeping the old secret in a verifier allow-list, with a grace window equal to your longest token lifetime (typically 15 to 60 minutes). In jsonwebtoken:
const ACTIVE = process.env.JWT_SECRET;
const PREVIOUS = process.env.JWT_SECRET_PREVIOUS;
function verify(token) {
try { return jwt.verify(token, ACTIVE, { algorithms: ['HS256'] }); }
catch { return jwt.verify(token, PREVIOUS, { algorithms: ['HS256'] }); }
}
3. Generating a 64-byte HS512 secret for a high-security backend. Choose 64 bytes, choose Base64URL, copy, and sign with algorithm: 'HS512'.
4. Distinguishing dev vs prod secrets. For tests, generate a 16-byte secret (still 128 bits, plenty for a CI run) and inject it via a fixture file excluded from version control.
Why 256 bits is the modern minimum
HS256 produces a 256-bit MAC. A key with fewer than 256 bits of entropy cannot supply enough uncertainty to match the MAC's security level, so brute-force and generic pre-image attacks become meaningfully cheaper. OWASP's JWT cheat sheet, the IETF's JWT BCP (RFC 8725), and NIST SP 800-107 all recommend at least the digest size of the chosen HMAC. Going beyond 256 bits (e.g. 64 or 128 bytes) buys headroom against future cryptanalytic improvements at negligible storage cost, a 64-byte secret is only 86 Base64URL characters.
The strength labels in this tool map to these bands:
- Weak (< 80 bits), never use for JWT or any production credential.
- Fair (80 to 127 bits), historical minimum, no longer recommended for HMAC.
- Good (128 to 191 bits), borderline for HS256; acceptable for short-lived, low-value tokens.
- Strong (192 to 255 bits), acceptable for many HMAC uses, but still below the HS256 floor.
- Very strong (โฅ 256 bits), the floor for HS256 and beyond.
How the random bytes are produced
Each secret is filled by crypto.getRandomValues(buffer), which draws from the platform CSPRNG (Chromium uses BoringSSL's RAND_bytes; Firefox uses NSS; Safari uses Common Crypto). Those implementations read hardware entropy (timing jitter, interrupt counts, RDRAND on x86, RNG on ARM) and mix it through a NIST-approved DRBG described in NIST SP 800-90A, suitable for key material, nonces, and salts.
Encoding is a deterministic bijection on bytes: the same 32 random bytes become 64 hex, 44 Base64, or 43 Base64URL characters depending on the option you pick; nothing about the bytes themselves changes.
Common mistakes to avoid
Hard-coding the secret in source. Committed secrets leak via Git history, CI logs, Docker images, and code-share tools. A single git push --force cannot erase a secret that has been pushed. Always load from an environment variable, a secrets manager (AWS Secrets Manager, GCP Secret Manager, HashiCorp Vault), or a KMS-encrypted blob.
Reusing one secret across environments. A leak from staging should not compromise production. Use a distinct secret per environment, per service, and ideally per tenant. Production tokens issued by a staging secret are an instant compromise.
Using the JWT in none algorithm mode. The alg: none header disables signature verification entirely. Several historical CVEs stem from libraries that accepted none by default. Configure your library to reject none and to enforce an algorithm allow-list, for example, only accept HS256 for shared-secret deployments.
Putting the secret in the browser bundle. Front-end JavaScript is delivered to every user. Any JWT verification done client-side is decorative; never sign tokens in the browser or expose signing keys to it. The browser has no secrets.
Skipping secret rotation. Rotate JWT signing secrets on a schedule (every 90 to 180 days is common) and immediately on suspected compromise. Support a grace window where two secrets are accepted so existing tokens stay valid until they naturally expire.
Choosing entropy by character count instead of bit count. A 64-character ASCII string drawn from a 95-character alphabet carries only ~420 bits, but a 64-character Base64URL string carries 384 bits regardless of the source alphabet. For JWT signing, the bit count of the decoded secret is what matters.
Mixing up Base64 and Base64URL. A standard-Base64 secret will still verify in most libraries because they accept both, but pasting a Base64 string into a URL or a JSON field can break parsers. When in doubt, use Base64URL.
Frequently Asked Questions
How long should my JWT secret be? At least 32 bytes (256 bits) for HS256, 48 bytes for HS384, and 64 bytes for HS512. Longer is fine, most teams pick 32 or 64 bytes and stay there. The strength label on this tool tells you instantly whether you have hit the floor for your algorithm.
What's the difference between Hex, Base64, and Base64URL? All three are lossless encodings of the same random bytes. Hex is the longest (2 chars per byte) and the easiest to copy by eye. Base64 is the shortest generic binary-to-text form but uses +, /, and =, which can break inside URLs and JSON without quoting. Base64URL swaps those for URL-safe characters and strips padding, that is the format JWT itself uses.
Are the secrets generated in my browser really random? Yes. The tool calls crypto.getRandomValues(), which is backed by the platform CSPRNG (Chromium uses BoringSSL's RAND_bytes; Firefox uses NSS; Safari uses Common Crypto). NIST SP 800-90A describes the underlying DRBG families these implementations draw from.
Should I pick HS256 or RS256? Use HS256 when one service both signs and verifies (most monoliths and internal APIs). Use RS256 when many verifiers need to check tokens but only the issuer should be able to mint them (federated SSO, third-party API access). RS256 needs a real key pair, not the random-bytes output of this tool.
Can I use this secret for OAuth client secrets or cookie signing? Yes, 256+ random bytes is the standard answer for any HMAC secret. The same secret should not be reused across unrelated services, but a single 32-byte Base64URL string is appropriate for cookie HMAC signing, webhook signing, and similar symmetric uses.
How do I rotate a JWT secret safely? Generate a new secret, deploy it as the active signer while keeping the old one as a verifier for a grace window (typically equal to your longest token lifetime), then retire the old secret. Libraries like jsonwebtoken (Node.js), python-jose (Python), and github.com/golang-jwt/jwt (Go) accept a list of secrets and try each in order.
Does storing the secret in environment variables count as safe? Environment variables beat hard-coding but are still readable by anything that can read /proc/<pid>/environ on the host, by anyone with kubectl exec or docker exec access, or by any log file that inadvertently captures process state. For production, prefer a secrets manager that supports audit logs, automatic rotation, and scoped access (AWS Secrets Manager, GCP Secret Manager, HashiCorp Vault, Doppler).
Is Base64 encoding the same as encryption? No. Base64 (and Base64URL) are reversible encodings, not encryption. Anyone who sees the string can decode it back to the original bytes. The protection comes from keeping the secret secret, not from the encoding. Encryption requires a key separate from the data being encrypted and a non-trivial algorithm (AES-GCM, ChaCha20-Poly1305, etc.).
What is the kid header and do I need it? The kid (key ID) header lets a JWT carry an identifier for the signing key it used. If you plan to rotate secrets, including a kid in the header tells the verifier which secret in its allow-list to consult, much cleaner than "try every secret in order". Many libraries support kid directly; you can set it to a UUID, a short timestamp, or any stable label.
Why does my library accept the secret as a string rather than bytes? Most JWT libraries take the secret as a UTF-8 string. The string is then hashed as bytes by the underlying HMAC implementation. As long as the string is a lossless encoding of your random bytes (Base64URL, Base64, or Hex), the bytes that HMAC sees are exactly the random ones you generated, encoding is purely presentation.
References
- RFC 7519, JSON Web Token (JWT). The core specification that defines the three-part
header.payload.signaturestructure and Base64URL encoding for the first two parts. - RFC 8725, JSON Web Token Best Current Practices. Recommends algorithm allow-lists, rejects
none, and discourages weak HMAC keys. - NIST SP 800-107, Recommendation for Applications Using Approved Hash Algorithms. Covers the security strengths of HMAC-SHA-256/384/512 and key-length guidance.
- NIST SP 800-90A, Recommendation for Random Number Generation Using DRBGs. The deterministic-random-bit-generator specification behind platform CSPRNGs.
- OWASP JSON Web Token Cheat Sheet. Operational guidance including the "at least 256 bits for HS256" rule and the
nonealgorithm warning. - NIST SP 800-63B, Digital Identity Guidelines. Discusses memorised secrets and entropy thresholds for credential strength bands.
Related Tools
- JWT Decoder, decode and inspect JWT headers, payloads, and claims.
- Hash Generator, generate SHA-1, SHA-256, and SHA-512 digests for any text.
- Base64 Encoder / Decoder, encode and decode arbitrary strings as Base64 and Base64URL.
- Password Generator, generate strong passwords with customisable character sets.
- UUID Generator, generate unique identifiers for non-secret use.