How to generate a secure password
August 11, 2026 · 8 min read
A password's strength against brute-force guessing comes down to one number: how many possible passwords an attacker would have to try, on average, before finding yours. That number is determined entirely by length and character-set size - a "clever" pattern a human finds memorable is, almost by definition, a pattern an attacker's dictionary already contains.
What actually makes a password strong
Entropy is measured in bits: each character you add, from an alphabet of size N, multiplies the number of possible passwords by N. A 12-character password using only lowercase letters (26 options per character) has roughly 56 bits of entropy; the same length using upper+lower+digits+symbols (94 options) has roughly 78 bits - millions of times more combinations for the same visible length. Length matters more than most people expect, and character-set variety matters less than length once you're already past a reasonable minimum.
Why Math.random() is the wrong tool
Math.random() is a pseudorandom number generator (PRNG) designed for speed and statistical distribution in things like games and simulations - not for unpredictability against an adversary. Its internal state is typically seedable and, in some JavaScript engines, has been shown to be predictable from a handful of observed outputs. That's a fine tradeoff for shuffling an array; it's a real vulnerability for anything where an attacker benefits from guessing your next "random" value, including passwords, tokens, and session IDs.
crypto.getRandomValues and why it's different
The Web Crypto API's crypto.getRandomValues() is backed by the operating system's cryptographically secure random number generator (CSPRNG) - the same source used to generate TLS session keys. It's specifically designed so that observing any number of past outputs gives an attacker no advantage in predicting future ones. This is the correct source for anything security-sensitive generated in a browser: passwords, API keys, UUIDs, nonces.
const bytes = new Uint8Array(20);
crypto.getRandomValues(bytes); // cryptographically secure
// vs.
Math.random(); // fine for games, not for secrets
Length vs character set
Adding symbols to a password's allowed character set helps, but adding four more characters of length usually helps more, because length compounds multiplicatively while character-set size only helps per-character. A 20-character password using just letters and digits generally beats a 12-character password stuffed with symbols, while also being easier for a password manager to autofill without special-character quoting issues some legacy systems still have.
Practical guidance
Let a password manager generate and store a long, fully random string for anything that supports pasting - there's no benefit to a password being memorable if you never have to type it. Reserve human-memorable passphrases (a handful of random dictionary words) for the small number of cases where you genuinely must type a password from memory, like your device's own unlock passcode or your password manager's own master password.
FAQ
- How long should a generated password be?
- 16 characters or more is a reasonable default for most accounts using a full character set; go longer for anything high-value, and use your service's maximum allowed length where practical.
- Do I need symbols in my password if it's already long?
- Symbols help, but a longer password without symbols is generally stronger than a shorter one with them - length has a bigger multiplicative effect on total guesswork than character-set variety.
- Is a randomly generated password safe if generated in a browser tab?
- Yes, provided it uses crypto.getRandomValues (not Math.random) and the value is never transmitted anywhere - generation happening locally doesn't weaken the randomness itself.