▸ Free tool
Secret & API Key Generator.
Cryptographically secure secrets, API keys, and passphrases — drawn from crypto.getRandomValues, never Math.random. Nothing is transmitted, nothing is logged.
▸ Local only
Generated in this tab with the browser CSPRNG. No request is made, no value is stored. Reload the page and they are gone for good.
Preset
128-word list · exactly 7 bits per word · joined with dashes
0 bits
Strength · —
—
Alphabet: —
The randomness comes from the OS, not from JavaScript
crypto.getRandomValues() is not a JavaScript
random number generator. It is a thin wrapper over the platform CSPRNG —
getrandom(2) on Linux,
BCryptGenRandom on Windows,
SecRandomCopyBytes on macOS — the same source
your server reaches for when it runs openssl rand. It is seeded from hardware entropy, it is continuously reseeded by
the kernel, and its output does not leak its internal state.
Math.random() fails all three of those. V8 implements
it as xorshift128+, seeded once when the context is created and never reseeded.
Its 128-bit state is recoverable from a modest run of consecutive outputs,
and once you have the state you can compute every value it will ever return
— forwards and backwards. That is fine for a confetti animation and a full
compromise for a session token. This page never calls it. Not for the strings,
not for the passphrases, not for anything.
| Math.random() | crypto.getRandomValues() | |
|---|---|---|
| Source | xorshift128+ in V8 | OS CSPRNG |
| State recoverable from output | Yes — a short run is enough | No |
| Reseeded | Once, at context creation | Continuously, by the kernel |
| Uniform after % n | No | No — still needs rejection sampling |
| Safe for secrets |
Why plain byte % length is a bug
A Uint8Array gives you values 0–255, and your
alphabet is almost never a divisor of 256. Take 62 alphanumeric characters:
256 = 4 × 62 + 8. Bytes 0–7 land on the same index as bytes 62–69, 124–131,
186–193 and 248–255 — five routes each — while every other index
has only four. The first eight characters of your alphabet show up roughly
25% more often than the rest.
That is not a catastrophic break, but it is a free ordering hint for
anyone building a guess list, and it quietly shaves entropy off every
secret you issue. The fix is rejection sampling and it costs nothing but
a few discarded bytes — about 3% of draws for a 62-character alphabet,
30% for the full 89-character one. Compute limit = Math.floor(256 / size) * size, throw away any byte at or above limit,
and take the modulo of what survives. Every index then has exactly equal
probability. That is what runs when you click Generate above. Hex and
base64url skip the rejection entirely, because 16 and 64 both divide
256.
What 128 bits actually buys you
Entropy is length × log₂(alphabetSize), and
the readout above shows the exact figure for whatever you have
configured. 128 bits means 3.4 × 10³⁸ candidate values. Give an attacker
a billion machines each testing a trillion candidates per second — 10²¹
guesses a second, which nobody on earth has — and the expected time to
land on yours is still around five billion years.
So 128 bits ends the conversation. 32 hex characters is exactly 128
bits. 22 alphanumeric characters is 131. A v4 UUID carries 122 — close enough to the bar that people reach for one as an API
key. Don't. UUIDs end up in URLs, access logs, and error messages precisely
because they are built to be identifiers, not secrets. Going past 128 bits
is not more secure either, it is a longer line in your .env, and it does nothing about the way secrets are actually compromised,
which is leaking rather than guessing. The symbol set here also
deliberately omits quotes, backticks, backslashes and spaces: they buy
well under a bit per character and cost you an afternoon the first time
a secret containing a backtick passes through a shell script, a dotenv
parser and a YAML file.
Generating is the easy part
The value above is worth nothing the moment it lands somewhere durable
and unencrypted. It belongs in a secret manager — Vault, AWS Secrets
Manager, Doppler, 1Password, or your platform's encrypted environment store if you self-host — injected at boot, never committed. If you have ever run
git add -A in a directory containing a real
.env, go check your history before you read
further.
Rotation is a design decision, not a chore. Your verifier has to accept the old value and the new one during an overlap window; if it cannot, "rotating" is a synonym for "brief outage", which is exactly why so many teams never rotate anything. Give every environment its own value — a staging key that also opens production is one leaked CI log away from being a production breach. Rotate on a schedule, on offboarding, and immediately on suspicion. "I think it's fine" is not an incident response.
Questions, answered.
Is it safe to generate secrets in a browser?
Yes, as long as the generator uses the platform CSPRNG and never sends the value anywhere. This page calls crypto.getRandomValues, which is backed by the same operating-system entropy source your server reaches for, and the generated values never leave the tab — no network request, no analytics event, no logging. Open devtools and watch the network panel while you click Generate. For a root signing key on a hardened host, generating on that host with openssl rand is still the tighter move.
Why is Math.random() unsafe for passwords and API keys?
Math.random() is a fast non-cryptographic PRNG — V8 implements it as xorshift128+ — seeded once when the context is created and never reseeded. Its internal state can be recovered from a modest run of outputs, and once an attacker has the state they can compute every value it will ever return, forwards and backwards. That is fine for shuffling a carousel and catastrophic for a session token, a password-reset link, or an API key.
How many bits of entropy does an API key need?
128 bits is the standard bar and there is very little reason to exceed it. That is 32 hex characters, 22 alphanumeric characters, or 16 raw bytes. Below roughly 64 bits you are inside reach of a determined offline attacker with commodity GPUs; above 128 you are only making your .env line longer, because the realistic compromise is the key leaking, not the key being guessed.
What is modulo bias, and does this generator avoid it?
Modulo bias is what you get when you map a random byte onto an alphabet that does not divide 256 evenly. With a 62-character alphabet, 256 = 4 × 62 + 8, so the first eight characters come up five times per 256 bytes while the rest come up four — about 25% more often. This tool computes limit = Math.floor(256 / alphabetSize) * alphabetSize, discards every byte at or above that limit, and only then takes the modulo, so each character is exactly equally likely.
Are the passphrases here as strong as Diceware?
No, and I would rather say so on the page than let you assume otherwise. The wordlist embedded here is 128 words, which is exactly 7 bits per word, so an eight-word passphrase is 56 bits. The EFF Diceware list is 7,776 words — about 12.9 bits per word — so six Diceware words beat eleven words from this list. Use passphrase mode for things a human has to type and remember, and random-string mode for anything a machine reads.
Where should I store the secret after generating it?
In a secret manager — Vault, AWS Secrets Manager, Doppler, 1Password, or your platform's encrypted environment store — and nowhere else. Not in the repository, not in a Slack message, not in a ticket. If a secret has ever touched shell history, a screen share, or a chat log, treat it as burned and rotate it. Rotation only works if your verifier accepts the old and the new value during an overlap window, so build that before you need it.
Keep reading
- Tool UUID Generator Same CSPRNG, different shape — v4 UUIDs in bulk.
- Tool Hash Generator SHA-256 and friends, for when you need to store a digest instead.
- Article Self-hosting a SaaS on Coolify Where environment secrets actually live once you leave Heroku.
- Article The API gateway in an AI stack Where API keys get issued, scoped, and revoked.
▸ Everything on this page runs client-side. No secret is transmitted, stored, or logged.