Generating passwords and tokens in the browser
Published: 2026-07-18
How to create strong random passwords and API tokens with Web Crypto, character classes, ambiguous-character exclusion, and local-only tools—without Math.random or a server.
Passwords and opaque tokens should come from a cryptographically secure random source. In the browser that means the Web Crypto API (crypto.getRandomValues), not Math.random(). Generating them locally—in your tab, with no upload—keeps secrets off third-party servers while you draft credentials for apps, test fixtures, or one-off API keys.
This guide covers entropy in plain language, how character sets affect strength, practical presets (strong password vs PIN vs alphanumeric), and when to use a free-form string instead of a structured ID like UUID or NanoID.
Passwords vs tokens vs identifiers
| Kind | Goal | Typical shape |
|---|---|---|
| Password | Human enters it (or a password manager stores it) | Mixed letters, digits, symbols; length often 12–64 |
| API / session token | Machine copies it into headers or config | Often alphanumeric or URL-safe; length sized for entropy, not readability |
| Public identifier | Names a resource; not a secret by itself | Fixed formats: UUID v4, ULID, NanoID |
A random string can serve any of these roles, but authorization still matters: hard-to-guess IDs are not a substitute for access control. Prefer structured ID generators when you need standard formats or short URL-friendly keys; use a random string generator when you control the alphabet (symbols, PIN digits, custom extras).
Why Math.random() is the wrong tool
Math.random() is fine for UI animations and shuffle demos that are not security-sensitive. It is not a CSPRNG (cryptographically secure pseudorandom number generator). Password and token generation should use:
const bytes = new Uint8Array(16);
crypto.getRandomValues(bytes);
Browsers implement getRandomValues with OS-backed entropy. Mapping those bytes onto a character alphabet should use rejection sampling (or an equivalent unbiased method) so every allowed character is equally likely—no modulo bias that slightly favors some symbols.
The Random String Generator follows that pattern: getRandomValues plus rejection sampling over your effective alphabet.
Entropy without the jargon overload
Rough rule of thumb for a password drawn uniformly from an alphabet of size (R) and length (L):
[ E \approx L \times \log_2(R) \text{ bits} ]
Examples (order of magnitude):
| Alphabet | (R) | Length 16 | Approx. bits |
|---|---|---|---|
| Digits only | 10 | 16 | ~53 |
| Lowercase | 26 | 16 | ~75 |
| Letters + digits | 62 | 16 | ~95 |
| Letters + digits + common symbols | ~80+ | 16 | ~100+ |
More length usually helps more than adding a few exotic symbols. A 16-character mixed password with a large alphabet is typically far stronger than an 8-character password stuffed with punctuation. Policies that force “one uppercase, one digit, one symbol” without enough length still produce weak passwords if (L) is small.
“Require at least one of each class”
Guaranteeing one uppercase, one lowercase, one digit, and one symbol avoids the rare (but annoying) all-lowercase draw. It slightly reduces the raw combinatorial space versus pure uniform sampling, but for practical lengths the trade-off is usually acceptable—and matches what many site policies expect.
If you enable that rule, length must be at least the number of enabled classes (after ambiguous exclusions remove empty classes).
Character classes and ambiguous lookalikes
Common pools:
| Class | Example set |
|---|---|
| Uppercase | A–Z |
| Lowercase | a–z |
| Digits | 0–9 |
| Symbols | e.g. !@#$%^&*()-_=+[]{};:,.?/ (spaces are often omitted so copy/paste stays reliable) |
Ambiguous characters are glyphs that humans (and fonts) confuse: 0 / O / o, 1 / l / I, |, and similar. Excluding them is useful when someone will type the password from a screen or printout. For machine-only tokens stored in a password manager or vault, keeping the full alphabet maximizes entropy per character—exclusion is optional.
You can also add extra allowed characters to widen the pool for a specific system (for example a rare punctuation mark a legacy API accepts).
Practical presets
| Preset | Typical options | When to use |
|---|---|---|
| Strong password | All classes, ambiguous off, require each class, length ~16+ | Human or password-manager credentials |
| Letters + digits | No symbols | Systems that reject punctuation; alphanumeric API keys |
| PIN (digits only, length 6) | Digits only | Device unlocks / short codes — never as an account password |
| Custom | Whatever you enable | Match a vendor’s documented charset and length |
Batch generation (many strings at once) is handy for seeding test users or rotating a set of lab tokens. Treat bulk output like any other secret: clear the clipboard and the page when finished.
Local generation and trust
Online “password generators” that send options to a server add an unnecessary trust surface. Prefer tools that:
- Use Web Crypto in the browser.
- Do not transmit length, alphabet, or output.
- Let you see the effective alphabet before you generate.
LocalTools’ Random String Generator runs entirely in your browser: presets, length 4–256, batch 1–500, ambiguous exclusion, and “require each class.” Nothing is uploaded or stored server-side.
If you later need to hand a secret to someone else over a link without putting it in chat history, see Secret Share (fragment-based sharing). For structured public IDs rather than free-form secrets, use UUID, ULID, or NanoID.
Common pitfalls
- Short length with a “complex” charset — complexity rules do not fix an 8-character ceiling.
- Reusing generated passwords across sites — generate once per account; a password manager is the right storage layer.
- Using PIN-style digit strings as API secrets — too little entropy for anything network-facing.
- Confusing IDs with secrets — a UUID v4 is an identifier; protect resources with real auth even if IDs look random.
- Generating on an untrusted shared computer — local processing still leaves traces in memory, screen, and clipboard on that device.
Try it in the browser
Use the Random String Generator to:
- Pick Strong password, alphanumeric, or PIN, or tune classes yourself.
- Set length, optionally exclude ambiguous characters, and require coverage of each class.
- Generate one string or a bulk list, then copy locally—entropy stays on your device.
Related reading: NanoID vs UUID (size and alphabet) for choosing ID formats, and UUID versions (and when v4 is enough) when you need a standard 128-bit identifier instead of a custom password alphabet.