Skip to content
Toolblip
← Blog
Developer Tools5 min read·

How to Generate Random strings Securely in JavaScript

Learn how to generate random strings in JavaScript using crypto-secure methods. Covers UUIDs, random tokens, password generators, and common security pitfalls.

Random strings are everywhere in software — session tokens, password reset links, API keys, UUIDs. Getting them wrong creates security vulnerabilities that are hard to catch. This guide shows you how to do it properly.

Why It Matters

Computers are deterministic. Generating "random" strings with Math.random() or Date.now() isn't truly random — it's pseudorandom, predictable, and exploitable. If you use Math.random() to generate a password reset token, an attacker who can guess the seed can reset any user's password.

Rule: always use the Web Crypto API for security-sensitive randomness.

Generate a UUID v4

The simplest secure use case — a unique identifier with enough entropy that guessing is impossible.

// Modern browsers and Node.js 19+
const uuid = crypto.randomUUID();
console.log(uuid); // "f47ac10b-58cc-4372-a567-0e02e2d5f6b1"

// Node.js fallback (all versions)
import { randomUUID } from 'crypto';
const uuid = randomUUID();

Why this is secure: 122 bits of cryptographically strong entropy from the OS random number generator. Brute-forcing is computationally infeasible.

Generate a Random Token

For API keys, session tokens, or password reset links:

// Generate a 32-byte (256-bit) random token, base64 encoded
function generateToken(lengthBytes = 32) {
  const bytes = crypto.getRandomValues(new Uint8Array(lengthBytes));
  return btoa(String.fromCharCode(...bytes))
    .replace(/\+/g, '-')
    .replace(/\//g, '_')
    .replace(/=/g, '');
}

const token = generateToken(); // "T8f9KwH3xLR2QpVl_YN7A..."

Key points:

  • crypto.getRandomValues() is the browser and Node.js API for secure randomness
  • Use Uint8Array to get raw random bytes
  • Use base64url encoding (not plain base64) for URL-safe tokens
  • Strip padding (=) to keep it compact

Generate a Random Password

function generatePassword(length = 16) {
  const charset = {
    lowercase: 'abcdefghijklmnopqrstuvwxyz',
    uppercase: 'ABCDEFGHIJKLMNOPQRSTUVWXYZ',
    numbers: '0123456789',
    symbols: '!@#$%^&*()_+-=[]{}|;:,.<>?',
  };

  const allChars = Object.values(charset).join('');
  const entropy = new Uint8Array(length);
  crypto.getRandomValues(entropy);

  let password = '';
  for (let i = 0; i < length; i++) {
    password += allChars[entropy[i] % allChars.length];
  }

  // Ensure at least one char from each category
  const required = [
    charset.lowercase[entropy[0] % 26],
    charset.uppercase[entropy[1] % 26],
    charset.numbers[entropy[2] % 10],
    charset.symbols[entropy[3] % charset.symbols.length],
  ];
  // Replace first 4 chars with required, rest with random
  return required.join('') + password.slice(4);
}

console.log(generatePassword()); // "Ab3@xK9LmNopQ2rs"

Note: This approach has a slight bias (modulo arithmetic isn't perfectly uniform), but for passwords it's negligible. For cryptographic keys, use a proper CSPRNG.

Generate a Cryptographic Key

For signing tokens, encrypting data, or any cryptographic purpose:

// Generate a 256-bit (32 byte) key for AES-256
const keyBytes = crypto.getRandomValues(new Uint8Array(32));
const keyHex = Array.from(keyBytes)
  .map(b => b.toString(16).padStart(2, '0'))
  .join('');

console.log(keyHex); // "a4f2c8d3e9b1..." (64 hex chars)

// For use with SubtleCrypto
crypto.subtle.importKey(
  'raw',
  keyBytes,
  { name: 'AES-GCM' },
  false, // not extractable
  ['encrypt', 'decrypt']
);

Common Mistakes to Avoid

Math.random() for Tokens

// NEVER do this
const token = Math.random().toString(36).substring(2);
// Predictable and low entropy

Math.random() is a PRNG (pseudo-random number generator) with only ~58 bits of state. It's fine for UI randomness (animations, shuffling), not security tokens.

Date.now() or timestamp in Tokens

// NEVER do this
const token = btoa(Date.now() + Math.random());
// Entirely predictable — attacker knows approximately when token was created

❌ Short Tokens

A 6-character alphanumeric token has only ~77 bits of entropy (log2(62^6)). That's breakable with commodity hardware in hours. Use at least 128 bits (22 base64 characters) for security-sensitive tokens.

❌ Sequential IDs as Secrets

Auto-increment IDs, UUID v1 (time-based), or any enumerable ID are not secrets. They look random but aren't.

Quick Reference

Purpose Method Bits of Entropy
UUID crypto.randomUUID() 122 bits
API token crypto.getRandomValues() + base64url 256 bits
Password crypto.getRandomValues() with charset ~100 bits
Cryptographic key crypto.getRandomValues() 256 bits
Nonce/IV crypto.getRandomValues() 96–256 bits

In Node.js

import { randomBytes, randomUUID } from 'crypto';

// Random bytes
const bytes = randomBytes(32); // Buffer of 32 random bytes

// UUID
const uuid = randomUUID();

// Hash-based (for deterministic tokens with a secret)
import { createHmac } from 'crypto';
const token = createHmac('sha256', secret)
  .update(randomBytes(32).toString('hex'))
  .digest('hex');

Useful Tools

No data leaves your browser. Everything runs client-side using the Web Crypto API.

#javascript#security#random#uuid#tokens#web-development

Toolblip Team

Writing about developer tools, web performance, and the tools that make building faster.

More in Developer Tools