Random token generator
Generates secrets from the browser CSPRNG — hex, base64url or a custom alphabet, plus EFF diceware passphrases — with entropy in bits.
192.0 bitsAverage time to find it, at three guessing rates. The spread between them is larger than any difference the secret itself makes.
- Against a login that rate-limits — 10 guesses/s
10^49 years - Against a leaked slow hash (bcrypt, argon2) — 10⁴/s
10^46 years - Against a leaked fast hash (SHA-256, MD5) — 10¹²/s
10^38 years
Drawing from 64 characters, so each one carries 6.00 bits.
What this tool does
It produces secrets: values whose only defence is that nobody can guess them. Pick an alphabet and a length for an API key or a database password, or switch to a passphrase drawn from a published wordlist for something a person has to type. Every result is generated in your browser and shown with the one number that describes its strength honestly.
This is a different job from the UUID generator on this site. A UUID has to be unique, so that two records never collide; a secret has to be unguessable, which is a stronger requirement and a different failure. A predictable identifier is harmless. A predictable secret is an open door.
Where the randomness comes from
Everything here draws from crypto.getRandomValues, the browser’s cryptographically secure random generator, which is seeded from the operating system’s entropy pool — the same source that openssl rand and /dev/urandom use.
The alternative, Math.random, is not a security function and has never claimed to be. It is a fast pseudo-random generator with a small internal state, and in every current engine that state can be recovered from a short run of outputs, after which every past and future value is known. A token built from it looks exactly as random as a real one; the difference only shows up when someone bothers to look.
A reasonable question is whether a web page is the right place to generate a production secret at all. The generation itself is sound: it is the platform CSPRNG, the page is static, and nothing is transmitted. The parts worth thinking about are the ones around it — a secret that goes through the clipboard may be readable by other applications, and one pasted into a terminal usually lands in the shell history. Those are the same considerations as any other method.
The bias hiding in the obvious implementation
Turning random bytes into characters looks like a one-liner: take a byte, take it modulo the alphabet size, index into the alphabet. It is subtly wrong for every alphabet whose size does not divide 256 evenly, and the output gives no sign of it.
With 62 alphanumeric characters, 256 does not divide evenly: 62 goes into 256 four times with 8 left over. Those 8 leftover byte values — 248 to 255 — fold back onto the first 8 characters of the alphabet, so each of those gets five chances out of 256 while the rest get four. The first eight characters are about 25% more likely than the others.
The fix is rejection sampling: discard a draw that lands in the leftover tail and draw again, rather than folding it back in. It costs about one extra draw in thirty-two for a 62-character alphabet and nothing at all for hex or base64url, whose sizes are powers of two and therefore have no tail. This tool rejects; the effect is not visible in any single token, which is exactly why it is worth stating.
Entropy, which is the only honest measure
Entropy in bits says how large the space of equally likely secrets is: n bits means 2^n possibilities. It is additive and easy to compare, and it says nothing about how fast anyone can search that space — which is a feature, because that part depends on things a generator cannot know.
The arithmetic is deliberately simple. Each character contributes log2(alphabet size) bits, and each word contributes log2(wordlist size), so:
- A hex character is 4 bits, so a 32-character hex token is exactly 128 bits — an AES-128 key written out.
- A base64url character is 6 bits, so 22 characters clear 128 bits and 43 clear 256.
- An alphanumeric character is about 5.95 bits; excluding the look-alikes drops the alphabet to 58 and the character to 5.86, which costs roughly one character of length every twelve.
- A word from the EFF long list is 12.925 bits, because the list has 7776 entries, which is 6^5 — five dice rolls.
- A word from the EFF short list is 10.34 bits, from 1296 entries, which is 6^4.
A common target is 128 bits, which is where brute force stops being a strategy rather than merely being expensive. That is 32 hex characters, 22 base64url characters, or 10 words from the EFF long list.
Why there is no single "time to crack"
A secret does not have a cracking time. The pair of a secret and whatever is guarding it has one, and the guard matters far more than the secret. The same value that would take longer than the universe has existed to find through a login form falls in an afternoon if it was stored as an unsalted SHA-256 and the database leaked.
So three rates are shown rather than one number, and each is named:
- Ten guesses a second, against a login that rate-limits. This is the realistic ceiling for an attacker who has to go through your service.
- Ten thousand guesses a second, against a leaked password hash built to be slow — bcrypt at a modern cost, or argon2. The slowness is the entire point of those functions.
- A trillion guesses a second, against a leaked hash that was never meant for passwords. SHA-256 and MD5 are designed to be fast, and a rig of GPUs is very fast indeed.
The rates are rounded to powers of ten deliberately. Anything more precise would suggest a measurement of one particular attacker, when the useful information is the eleven orders of magnitude between the first row and the last. If a secret is comfortable in all three, the question is settled without needing the exact figures.
Each figure is the average, which is half the space rather than all of it — a search finds the answer halfway through on average. And past a million years the answer is given as an order of magnitude, because "four hundred trillion years" is not a duration anyone can compare. The universe is about 10^10 years old, which makes a useful anchor for the rows that reach that far.
Passphrases, and where their strength actually comes from
A passphrase is strong for exactly one reason: several words were chosen at random from a large list. It is not strong because it is long, and it is not strong because it looks like language. Six random words from a 7776-word list is about 77 bits; six words a person thought of is worth far less, because people do not choose uniformly and an attacker knows the same things about common phrases that you do.
The two lists here come from the EFF and are the published diceware lists, downloaded unchanged. They are not lists assembled here, and that matters: a wordlist someone invented has unknown size, unknown overlap with other lists, and no way to check the entropy claim made about it.
- The long list has 7776 words, one for every roll of five dice, and gives 12.925 bits per word.
- The short list has 1296 words, one for every roll of four dice, and gives 10.34 bits per word. Its words are shorter — none is over five letters — which makes it easier to type at the cost of needing more words for the same strength.
A repeated word in a passphrase is not a flaw and is not regenerated here. Each draw is independent, so any particular pair of words is exactly as likely as any other; refusing repeats would shrink the space of possible passphrases and make them slightly weaker, not stronger.
Both EFF lists contain a handful of hyphenated entries — t-shirt, yo-yo, drop-down, felt-tip. If the separator is also a hyphen, a passphrase containing one of them cannot be split back into its words unambiguously. It is a display problem rather than a security one, and choosing a space or a full stop as the separator avoids it entirely.
The options that cost entropy, and the one that does not
Excluding the look-alike characters trades strength for legibility, and the trade is visible. Removing 0, O, I and l takes the alphanumeric alphabet from 62 characters to 58 — which is, exactly, the base58 alphabet Bitcoin uses, and for the same reason. Each character drops from 5.95 to 5.86 bits, so a token needs about one extra character every twelve to stay as strong. That is usually worth it for anything a person will read off a screen and type somewhere else.
The option is offered only where it means something. Hex and base64url are encodings, not character sets: their alphabets are fixed by a specification, and hex without 0 is not hex any more — nothing would be able to decode it.
Capitalising each word of a passphrase adds nothing at all, and the strength figure here deliberately does not move when you switch it on. It is the same transformation applied every time, so it does not create a single new possibility: an attacker who knows the phrase is capitalised is exactly where they started. The option exists because password fields still demand a capital letter, not because it helps.
Choosing a length
For anything a machine handles — API keys, session tokens, webhook secrets, database passwords — there is no reason to be frugal. 32 hex characters or 22 base64url characters gives 128 bits, and going further costs only bytes in a config file.
For anything a person types, the constraint is different and a passphrase is usually the better shape. Six words from the long list is stronger than a twelve-character random password and dramatically easier to get right on the first attempt, which matters more than it sounds: a secret people mistype is a secret people write down.
For a numeric code the honest reading is that four digits is 13 bits and can be exhausted in seconds by anything that is not rate-limiting. A PIN is only ever safe because of the lockout policy around it, never because of its own strength.
Frequently asked questions
- How long should an API key be?
- Aim for 128 bits of entropy or more, which is where brute force stops being a strategy. That is 32 hex characters, 22 base64url characters, or 43 base64url characters if you want 256 bits. For a value only software ever handles, the longer option costs nothing.
- Is this safer than generating a secret with Math.random?
- Yes, and the difference is not a matter of degree. Math.random is a pseudo-random generator with a small state that current engines allow to be recovered from a short run of outputs, after which every value it will ever produce is known. This tool uses crypto.getRandomValues, the platform CSPRNG, which is the same source openssl rand draws from.
- Why do you not show a single "time to crack"?
- Because there is no such number. The same secret is unreachable behind a login that rate-limits and falls quickly behind a leaked fast hash — eleven orders of magnitude apart. A single figure has to pick one assumption and then hide it, and readers remember the number rather than the assumption. Three named rates put the assumption where you can see it.
- Are passphrases weaker than random strings?
- No — the strength depends only on how many words are drawn from how large a list, and both are shown. Six words from the EFF long list is about 77 bits, more than a ten-character random password. What weakens a passphrase is choosing the words yourself, which these are not.
- Should I exclude the look-alike characters?
- If a human will read the secret off a screen and type it somewhere else, yes: the cost is small and a misread token is a support ticket. If only software will handle it, there is no reason to. Removing 0, O, I and l takes the alphabet from 62 characters to 58, which is exactly the base58 alphabet, and costs about one character of length every twelve.
- Does capitalising a passphrase make it stronger?
- No. It is the same change applied every time, so it does not add a single new possibility to the space of passphrases. The entropy figure here stays put when you switch it on, which is the accurate behaviour. The option is there because some password fields insist on a capital letter.
- Is anything I generate sent to a server?
- No. Generation runs entirely in your browser using the platform random generator, nothing is uploaded or logged, and it works with no network connection. The tokens are not stored anywhere — reloading the page produces new ones and the old ones are gone.