How to Generate Random Passwords (Secure Methods)

March 22, 2026 · 8 min read

You need a strong password. Maybe you're creating a database credential, generating an API key, or just signing up for yet another service. You know "password123" won't cut it — but how do you actually generate a password that's cryptographically secure?

This guide covers the right way to generate random passwords in JavaScript, Python, and the command line, explains the math behind password strength, and shows you why Math.random() is never safe for security.

Why Math.random() Is Not Secure

The most common mistake: using Math.random() for password generation. Here's why that's dangerous:

Instead, use a cryptographically secure random source:

Language Insecure Secure
JavaScript (browser) Math.random() crypto.getRandomValues()
JavaScript (Node.js) Math.random() crypto.randomBytes()
Python random.choice() secrets.choice()
Go math/rand crypto/rand

JavaScript: Secure Password Generator

Browser (Web Crypto API)

function generatePassword(length = 16, options = {}) { const { uppercase = true, lowercase = true, numbers = true, symbols = true } = options; let charset = ''; if (lowercase) charset += 'abcdefghijklmnopqrstuvwxyz'; if (uppercase) charset += 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'; if (numbers) charset += '0123456789'; if (symbols) charset += '!@#$%^&*()_+-=[]{}|;:,.<>?'; const array = new Uint32Array(length); crypto.getRandomValues(array); return Array.from(array, n => charset[n % charset.length]).join(''); } // Generate a 20-character password with all character types console.log(generatePassword(20)); // Example: "kR7#mP2$xL9&nQ4@wJ6!" // Numbers only (e.g., for a PIN) console.log(generatePassword(6, { uppercase: false, lowercase: false, symbols: false })); // Example: "847293"

Node.js

const crypto = require('crypto'); function generatePassword(length = 16) { const charset = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*()_+-='; const bytes = crypto.randomBytes(length); return Array.from(bytes, b => charset[b % charset.length]).join(''); } console.log(generatePassword(24)); // Even simpler — random hex string console.log(crypto.randomBytes(16).toString('hex')); // "a3f7c2e891d4b506f8a1e3c7d9b2f041" // Random base64 string (URL-safe) console.log(crypto.randomBytes(24).toString('base64url')); // "k7Rm2PxL9nQ4wJ6hB8vT3sY1uE5i"

Python: Secure Password Generator

import secrets import string def generate_password(length=16, use_symbols=True): charset = string.ascii_letters + string.digits if use_symbols: charset += string.punctuation # Ensure at least one of each required type password = [ secrets.choice(string.ascii_lowercase), secrets.choice(string.ascii_uppercase), secrets.choice(string.digits), ] if use_symbols: password.append(secrets.choice(string.punctuation)) # Fill remaining length password += [secrets.choice(charset) for _ in range(length - len(password))] # Shuffle to avoid predictable positions secrets.SystemRandom().shuffle(password) return ''.join(password) print(generate_password(20)) # Quick one-liner for a token print(secrets.token_urlsafe(32)) # 43-char URL-safe token print(secrets.token_hex(16)) # 32-char hex string

Command Line Methods

# Linux/macOS — using /dev/urandom openssl rand -base64 24 # 32-char base64 password openssl rand -hex 16 # 32-char hex password # Using /dev/urandom directly tr -dc 'A-Za-z0-9!@#$%' < /dev/urandom | head -c 20; echo # macOS — using security framework security random -c 20 # Python one-liner python3 -c "import secrets; print(secrets.token_urlsafe(24))" # Node.js one-liner node -e "console.log(require('crypto').randomBytes(24).toString('base64url'))"

Understanding Password Entropy

Password strength is measured in bits of entropy — the number of possible combinations expressed as a power of 2:

Entropy = length × log2(charset_size)
Charset Size Bits per char 12-char entropy 16-char entropy
Digits only 10 3.32 39.9 bits 53.2 bits
Lowercase 26 4.70 56.4 bits 75.2 bits
Alphanumeric 62 5.95 71.5 bits 95.3 bits
All printable ASCII 95 6.57 78.8 bits 105.1 bits

General guidelines:

A 16-character password using mixed case + digits + symbols gives you ~105 bits — very strong.

Passphrases: The Better Alternative

Random character passwords are strong but hard to remember. Passphrases — random word combinations — offer high entropy with better memorability:

# Python passphrase generator (Diceware-style) import secrets wordlist = [ "correct", "horse", "battery", "staple", "quantum", "forest", "bridge", "hammer", "violet", "orange", "rocket", "marble", "cosmic", "thunder", "garden", "silver", "dragon", "puzzle", "beacon", "crystal", "nebula", "falcon", "harbor", "zenith", # ... use a full Diceware or EFF wordlist (7776 words) ] def generate_passphrase(words=5, separator='-'): return separator.join(secrets.choice(wordlist) for _ in range(words)) print(generate_passphrase()) # Example: "cosmic-hammer-violet-beacon-falcon"

With a 7,776-word list (standard Diceware), each word adds ~12.9 bits of entropy. A 5-word passphrase gives ~64.6 bits — equivalent to a random 10-character mixed-case alphanumeric password, but much easier to type and remember.

Password Generation Mistakes to Avoid

  1. Using Math.random() or random.random() — these are predictable. Always use crypto-grade randomness.
  2. Modulo biasrandomByte % charsetLength introduces slight bias when the charset doesn't evenly divide 256. For most passwords this is negligible, but for high-security use, implement rejection sampling.
  3. Hardcoding seeds — never seed a PRNG with a fixed value or timestamp for password generation.
  4. Insufficient length — 8-character passwords are crackable with modern hardware. Use 16+ characters.
  5. Generating in the wrong layer — generate passwords server-side when possible. Client-side generation in JavaScript is fine for tools (like ours), but API keys and database passwords should be generated on the server.
  6. Logging passwords — never log, print, or store generated passwords in plaintext after use.
Bottom line: Use crypto.getRandomValues() in browsers, secrets in Python, or crypto.randomBytes() in Node.js. Generate at least 16 characters with mixed character types, or use a 5+ word passphrase from a large wordlist. Never use Math.random() for anything security-related.
Generate secure passwords instantly
Customizable length, character sets, and passphrase mode — all generated in your browser, nothing sent to a server.
Open Password Generator

Related Reading

Get New Tools in Your Inbox

We ship new free tools weekly. No spam, unsubscribe anytime.