Cryptographically secure random strings with rejection sampling — no modulo bias, no dependencies, works the same in the browser, Node.js and edge runtimes.
Two subtle bugs hide in most hand-rolled token generators:
Math.random()is predictable. V8's PRNG (xorshift128+) can be reconstructed from a few outputs — soMath.random()-based passwords, invite codes and share IDs are guessable.byte % charsetLenis biased. When the charset size doesn't divide 256 evenly (e.g. 62 or 36 chars), the lower characters appear slightly more often. Over millions of codes that's a real, exploitable skew.
unbiased-random-string fixes both: it draws from the Web Crypto CSPRNG (crypto.getRandomValues) and uses rejection sampling so every character is equally likely.
npm install unbiased-random-stringimport { randomString, randomId, randomCode, UNAMBIGUOUS, ALPHANUMERIC } from 'unbiased-random-string';
randomId(); // "Xk7Qp2mZ9rLa" — 12-char alphanumeric (~71 bits)
randomId(21); // longer id
randomCode(); // "K7P2QM" — 6-char human-typable code (no 0/O, 1/l/I)
randomString(32); // 32 chars from the unambiguous set (default)
randomString(16, ALPHANUMERIC) // pick any charset| Export | Set | Use |
|---|---|---|
ALPHANUMERIC |
A–Z a–z 0–9 (62) |
ids, tokens |
UNAMBIGUOUS |
alphanumeric minus 0 O 1 l I |
default — human-safe |
UPPER_CODE |
upper + digits, unambiguous | invite/redeem codes |
LOWER_CODE |
lower + digits, unambiguous | URL slugs / share IDs |
randomString(length, chars?) => string— the core;charsmust have 2–256 characters.randomId(length = 12) => string— alphanumeric.randomCode(length = 6) => string— uppercase + digits, unambiguous.
Map a byte 0–255 to a character with byte % charLen and the first 256 mod charLen characters get one extra chance each. So we compute maxValid = floor(256 / charLen) * charLen and reject any byte ≥ maxValid before mapping. Every accepted byte then lands on exactly one character with equal probability. The test suite verifies the distribution stays uniform for a deliberately awkward charset size.
Extracted from the production token/ID layer of quanta-study.de — the single source of truth for every share ID, invite code and temporary password.
MIT © Amos Matzke · quanta-study.de