# How to Generate a JWT Secret + API Key (Cryptographically Secure)

URL: https://pdfflare.com/blog/how-to-generate-jwt-secret-api-key
Published: May 6, 2026
Reading time: 10 min read

> Generate a JWT secret or API key in your browser using the Web Crypto API. Hex, base64, base64url, prefix presets, bulk. Free, no signup, never transmitted.

---

You're standing up a new service, the README says `JWT_SECRET=<your-secret-here>`, and the internet's top results suggest you run `openssl rand -base64 32`or paste 32 random keyboard mashes. The first works but requires a terminal; the second is dangerously low-entropy. There's a middle ground: a one-click random secret generator that uses the same browser CSPRNG that backs WebAuthn and TLS, with presets for the formats your stack expects.

In this guide you'll learn how to generate a JWT secret, an API key, a webhook signing secret, and an AES-256 encryption key online using [PDFFlare's Random Secret Generator](https://pdfflare.com/tools/dev/random-secret-generator). The tool works as a jwt secret generator (HS256 / HS384 / HS512), an api key generator online with custom prefixes, a random hex string generator for encryption keys, a webhook signing secret generator (Stripe-style whsec_ format included), a random base64 string generator for libsodium / KMS imports, an encryption key generator online for AES-256 keys, and a general-purpose secure random string generator for any other token need. Generation runs entirely in your browser via `crypto.getRandomValues()`; nothing is transmitted, logged, or stored.

## Why You Need a Cryptographically Secure Random Source

A JWT secret signs every token your auth service issues. If an attacker can guess the secret, they can forge tokens for any user. So “random” isn't a casual property — it's the entire security posture of your authentication system. Two ways people get this wrong:

- **Using `Math.random()`** (or any non-cryptographic PRNG) — these are seeded from system clocks or Mersenne Twister state and produce predictable output. Acceptable for shuffling cards in a game, never for secrets.
- **Using human-typed passwords**— “mySecret123!” has maybe 30 bits of entropy because it's drawn from the small set of memorable patterns humans pick. A 256-bit random secret has 256 bits, an unimaginably larger search space.

The right source is a CSPRNG (Cryptographically Secure Pseudo-Random Number Generator) seeded from the OS's entropy pool. In a browser that's `crypto.getRandomValues()`, which delegates to` /dev/urandom` on Linux/Mac and `BCryptGenRandom` on Windows. Same standard the browser uses internally for TLS handshakes and WebAuthn key generation.

## How to Generate a JWT Secret (Step by Step)

1. **Open the random secret generator.** Visit [/tools/dev/random-secret-generator](https://pdfflare.com/tools/dev/random-secret-generator).
2. **Click the JWT HS256 secret preset.** This sets length to 256-bit and format to base64 — exactly what JOSE-compliant JWT libraries (jsonwebtoken, jose, PyJWT, etc.) expect for HS256. For HS512, click JWT HS512 instead (512-bit base64).
3. **Copy the result.** Click the Copy button on the secret output row. The clipboard now holds your production JWT signing secret.
4. **Paste into your secrets manager.** For local dev, paste into `JWT_SECRET=...` in your` .env` file. For production, drop it into AWS Secrets Manager, GCP Secret Manager, Vercel/Railway env vars, or whatever your platform uses. Never commit the secret to git.

## API Key, Webhook Secret, and Encryption Key Workflows

### How to generate a secure API key online with a custom prefix

API keys benefit from a recognizable prefix — when a user accidentally pastes one into a chat or commits one to git, a prefix like `api_` or `sk_live_` makes it scannable. The API key preset produces a 256-bit base64url string with `api_` prepended: URL-safe (no +/= chars to escape), prefix-tagged for log scanning, and 256 bits of entropy. Or pick a custom prefix from the Prefix dropdown — Stripe live, Stripe test, GitHub PAT, webhook signing, or roll your own.

### How to generate a Stripe webhook signing secret format

Stripe webhook secrets look like `whsec_AbCdEfGhIjKl...` — a 256-bit value with a `whsec_`prefix. The Stripe webhook secret preset mirrors this exactly. Pair the result with PDFFlare's [HMAC Generator](https://pdfflare.com/tools/dev/hmac-generator) to test that your signing logic produces the same signature Stripe's SDK would. Use the same secret on both ends — your server signs, your receiver verifies, byte-perfect.

### How to generate an AES-256 encryption key in hex format

AES-256 needs a 256-bit key (32 bytes). The AES-256 encryption key preset produces 64 hex characters — paste straight into your encryption library, an HSM, KMS import, or a config file expecting hex. If you'd rather have base64 (libsodium prefers it), switch the format to Base64 and the same 32 random bytes encode as ~44 base64 characters with identical entropy.

### How to generate multiple API keys in bulk

Beta launches and key rotations need batches. Pick 10, 25, or 50 from the quantity selector and hit Generate — each secret is independently produced from a fresh `crypto.getRandomValues()` call. Click Copy all to put them all on the clipboard newline-separated; paste into a config file, a database seed, or a CSV ready for import.

## Choosing a Format: Hex vs Base64 vs Base64url vs Alphanumeric

Same entropy, different shape — pick the one your downstream tool expects:

- **Hex (lowercase / UPPERCASE)** — the most universal format. 2 chars per byte. Used by every CLI (`openssl rand -hex`, `xxd`, PowerShell's `Get-FileHash`) and most crypto libraries when you need a literal hex secret.
- **Base64** — denser (4 chars per 3 bytes). What most JWT libraries expect for HMAC secrets. The `+` and `/` chars sometimes need escaping in URLs.
- **Base64url (no padding)** — drops `=` padding and replaces `+/` with `-_`. Safe for URL params, JWT signature segments, and anywhere a regular base64 secret would need escaping.
- **Alphanumeric** — A-Z, a-z, 0-9 only. Useful when the secret will pass through systems that mangle symbols. Slightly less entropy per character than base64, but generated with rejection sampling so every char is uniformly distributed (no modulo bias).

## Common Mistakes

- **Reusing the same secret across environments.** Dev, staging, and prod each need their own JWT secret. If dev leaks, prod stays safe. Different secrets also mean a token signed in dev won't accidentally validate in prod.
- **Committing the secret to git.** Even in a private repo, secrets in git history are findable forever. Use `.env.local`(git-ignored) for dev and a secrets manager for prod. If you accidentally commit one, rotate immediately — assume it's public.
- **Picking a length below the algorithm requirement.** HS256 demands 256-bit minimum, HS512 demands 512-bit. The JWT library may not error on a short secret but JOSE validators will, and your security guarantee silently degrades.
- **Mixing up signing and encryption keys.** HMAC keys and AES keys are both “random 32 bytes” in shape but should never be reused — the security analysis assumes they're independent. Generate each fresh.

## Privacy: Secrets Stay in Your Browser

The whole point of generating secrets in a tool is that the tool can't know what you generated. PDFFlare's random secret generator runs `crypto.getRandomValues()`in your browser, fills a typed array with cryptographically random bytes, and formats them locally. There's no network call during generation — open DevTools → Network and watch the tab stay empty as you click Generate. The only persisted state is your format / length / prefix preferences in localStorage; generated secrets are NEVER stored. This is what makes the tool safe to use for production secrets, not just dev experiments.

## Related Tools

- [HMAC Generator](https://pdfflare.com/tools/dev/hmac-generator) — test that the secret you just generated produces the right webhook / JWT signature. Same algorithms (SHA-256 / 384 / 512), same key, byte-perfect output verified against RFC 4231 reference vectors.
- [JWT Decoder](https://pdfflare.com/tools/dev/jwt-decoder) — paste a token signed with your new secret to verify the header.payload structure decodes cleanly and standard claims (iss, sub, exp, iat) are what you expect.
- [UUID Generator](https://pdfflare.com/tools/dev/uuid-generator) — for IDs (request IDs, idempotency keys, primary keys), not for secrets. UUIDs are unique-not-unguessable; secrets are unguessable-not-unique. Different tools.
- [Password Generator](https://pdfflare.com/tools/dev/password-generator) — for HUMAN passwords (account login, master passwords). The Random Secret Generator is for SYSTEM secrets that humans never type. Use whichever matches who reads the output.

## Wrapping Up

Generating a secure random secret is a 30-second task that decides whether your authentication system can be forged tomorrow. Use a CSPRNG (which PDFFlare's [Random Secret Generator](https://pdfflare.com/tools/dev/random-secret-generator) uses), pick the format your stack expects, store the secret somewhere your code can reach but a git commit can't, and rotate when in doubt.

---

## Frequently asked questions

**Q: How long should a JWT secret be in 2026?**

A: RFC 7518 (JOSE) requires HS256 secrets to be at least 256 bits (32 bytes), HS384 needs 384-bit minimum, and HS512 needs 512-bit minimum. PDFFlare's JWT HS256 preset produces exactly 256 bits of base64; the JWT HS512 preset produces 512 bits. Going larger than the algorithm output size doesn't add meaningful security; going smaller reduces brute-force resistance and is flagged by JOSE-compliant libraries.

**Q: Is crypto.getRandomValues() safe for production secrets?**

A: Yes — it's the W3C Web Cryptography API CSPRNG, seeded from the operating system entropy pool (/dev/urandom on Linux/Mac, BCryptGenRandom on Windows). It's the same source the browser uses internally for TLS handshakes and WebAuthn key generation. Don't confuse it with Math.random(), which is a non-cryptographic PRNG and should never be used for secrets.

**Q: Why does an alphanumeric API key have less entropy than hex?**

A: Hex uses a 16-char alphabet (4 bits per char), so a 32-char hex string carries 128 bits of entropy. Alphanumeric uses a 62-char alphabet (~5.95 bits per char), so a 32-char alphanumeric string carries ~190 bits. Both are plenty for an API key. PDFFlare's tool shows the resulting bit count next to the format selector so you can pick consciously.

**Q: What's the difference between a JWT secret and an API key?**

A: A JWT secret signs and verifies tokens — it's shared between the issuer and verifier of JWTs and never sent to clients. An API key is sent BY clients to authenticate themselves to your API — clients hold it, your server checks it. Both should be cryptographically random, but they live in different parts of your system. Use the JWT HS256 preset for the former, the API key preset for the latter.

**Q: Can I generate a Stripe-compatible webhook signing secret?**

A: PDFFlare's Stripe webhook secret preset produces a `whsec_` prefix plus 256 bits of hex — the same shape as Stripe's published webhook secrets. It's NOT a real Stripe-issued secret (only Stripe's dashboard can issue those for actual webhook endpoints), but it's the right format for testing your signing/verification pipeline locally, building mock servers, or replicating the format in your own webhook system.

---

## About PDFFlare

PDFFlare is a free collection of online tools for working with PDFs, images, text, JSON, and developer utilities. All tools run client-side in your browser — no signup, no upload to our servers, no rate limits.

For the full site index, see https://pdfflare.com/llms.txt.
For the complete content dump in one file, see https://pdfflare.com/llms-full.txt.