crypto.getRandomValues is the Web Crypto method that overwrites an integer typed array with cryptographically strong random values and returns the same array. It is defined by the W3C Web Cryptography specification and is the only member of the Crypto interface that also works on pages served without HTTPS. One call can fill at most 65,536 bytes.
You allocate the array first, and the method fills it in place. The browser draws from a pseudorandom generator that is seeded from operating system entropy, so the output is suitable for tokens, salts and initialization vectors. The specification sets no minimum entropy and tells implementations to do their best.
const a = new Uint8Array(16);
console.log(crypto.getRandomValues(a) === a, a.length);
console.log(Array.from(crypto.getRandomValues(new Uint8Array(16)), b => b.toString(16).padStart(2, '0')).join('').length);
const big = new Uint8Array(65536); crypto.getRandomValues(big); console.log('65536 bytes ok');
for (const A of [Uint8Array, Uint16Array, Uint32Array, BigUint64Array]) {
const max = 65536 / A.BYTES_PER_ELEMENT;
try { crypto.getRandomValues(new A(max + 1)); } catch (e) { console.log(A.name, max + 1, e.name); }
}
try { crypto.getRandomValues(new Float32Array(1)); } catch (e) { console.log(e.name); }
Output from Node.js 22.22.0:
true 16
32
65536 bytes ok
Uint8Array 65537 QuotaExceededError
Uint16Array 32769 QuotaExceededError
Uint32Array 16385 QuotaExceededError
BigUint64Array 8193 QuotaExceededError
TypeMismatchError
Draw a Uint32 and reject values that would skew the result, instead of using a plain modulo. A 32-bit value has 4,294,967,296 possibilities, and 2 to the power 32 modulo 6 is 4, so a dice roll made with buf[0] % 6 favors the first four faces slightly. Rejection sampling removes the bias:
function randomInt(max) {
const limit = 2 ** 32 - (2 ** 32 % max);
const buf = new Uint32Array(1);
do { crypto.getRandomValues(buf); } while (buf[0] >= limit);
return buf[0] % max;
}
For max 6 the limit is 4294967292, so four values are discarded and the rest map evenly. The bias for small ranges is tiny, but it is easy to avoid, and it matters for large ranges.
No. Math.random is not designed to be unpredictable, and its algorithm is up to the engine. Use getRandomValues for session IDs, password reset tokens, API keys and anything an attacker would profit from guessing.