Every developer needs random strings — for API keys, session tokens, test data, temporary passwords, and dozens of other purposes. But there's a critical difference between a string that looks random and one that is actually random. If you're generating security-sensitive strings with Math.random(), you're doing it wrong.
This guide covers what makes a random string secure, how to calculate its strength, and how to generate one properly in any programming language.
What Makes a Random String "Secure"?
A secure random string must satisfy two requirements:
- Cryptographic randomness: The generator must use a CSPRNG (Cryptographically Secure Pseudo-Random Number Generator) that draws entropy from the operating system — not a deterministic algorithm like a linear congruential generator.
- Sufficient entropy: The string must be long enough and use a large enough character set to resist brute-force attacks.
CSPRNG vs PRNG: Why It Matters
A regular PRNG (like Math.random() in JavaScript or random.random() in Python) is pseudorandom — it uses a mathematical formula to produce numbers that appear random but are completely deterministic. If an attacker knows the algorithm and the seed value (the initial state), they can reproduce every "random" number the generator will ever produce.
A CSPRNG, on the other hand, is seeded with real entropy from the operating system — timing of keystrokes, mouse movements, disk I/O, hardware noise, and other unpredictable sources. Even if the algorithm is known, the output cannot be predicted.
Math.random() (JavaScript) · random.random() (Python) · rand() (C) · Math.random() (Java) · Any LCG-based generator
These are fine for games, simulations, and shuffling — but never for passwords, tokens, or keys.
Understanding Entropy
Entropy is the measure of unpredictability, expressed in bits. The formula is straightforward:
Here's what different character sets give you:
| Character Set | Characters | Bits per Character |
|---|---|---|
| Digits (0-9) | 10 | 3.3 bits |
| Hexadecimal (0-9, a-f) | 16 | 4.0 bits |
| Lowercase letters (a-z) | 26 | 4.7 bits |
| Alphanumeric (a-z, A-Z, 0-9) | 62 | 5.95 bits |
| Full ASCII printable | 94 | 6.55 bits |
So a 16-character string using the full ASCII set has: 16 × 6.55 = 104.8 bits of entropy. For comparison, AES-128 uses 128 bits. That 16-character random string is nearly as strong as a 128-bit encryption key.
How Much Entropy Do You Need?
- Session tokens: 128 bits minimum (the industry standard for web frameworks)
- API keys: 128-256 bits (32-64 hex characters)
- Password reset tokens: 128 bits (sent via email, expire in 1 hour)
- Encryption keys: 256 bits or more
- Test data / mock values: Whatever looks good (no security requirement)
Choosing the Right Character Set
More characters means more entropy per position — but also more complexity for humans. The right choice depends on your use case:
- API keys & tokens: Base64url (A-Z, a-z, 0-9, -, _) — 64 characters, URL-safe, no escaping needed
- Passwords (human-readable): Alphanumeric + symbols — maximum entropy per character
- Hex strings (for encoding): 0-9, a-f — commonly used for tokens that need to be hex-decoded
- Test data: Any set that matches your data format requirements
How to Generate Secure Random Strings
Online Random String Generator
The fastest method: use our Random String Generator Tool. Choose your character set, length, and quantity — get cryptographically random strings instantly.
JavaScript (Browser)
Node.js
Python
Command Line
Real-World Use Cases
1. API Keys
API keys should be long (32+ characters), URL-safe, and generated with a CSPRNG. Prefix them to identify the service (e.g., sk_live_abc123...) and store only the hash (never plaintext) in your database.
2. Session Tokens
Web session tokens need at least 128 bits of entropy. Most frameworks handle this automatically (Express uses 256-bit tokens, Django uses 128-bit), but if you're building custom authentication, don't cut corners.
3. Password Generation
The best passwords are long random strings — but humans struggle with them. Consider using diceware (random word combinations) for user-facing passwords and pure random strings for machine-to-machine credentials.
4. Test Data
For testing, you don't need cryptographic randomness — but a random string generator saves time. Generate fake emails, usernames, order IDs, or any placeholder data that looks realistic.
Common Mistakes
- Using timestamps or counters as "random" tokens: These are trivially predictable. An attacker can guess the next token in the sequence.
- Seeding a PRNG with the current time: This is common but insecure. If an attacker knows approximately when the seed was generated (which they usually do), the search space is tiny.
- Using the modulo bias shortcut: When mapping random bytes to a character set, simple modulo introduces bias if the character set size doesn't evenly divide 256. For security-critical applications, use rejection sampling instead.
- Reusing random strings: Every generated string should be fresh. Never recycle tokens, even if they're "no longer in use."
- Storing random tokens in plaintext: Hash them with SHA-256 before storing. If your database is compromised, the tokens are useless to the attacker.
Random String vs UUID vs Password
These three are often confused but serve different purposes:
- Random string: General purpose — any length, any character set, customizable. Use for API keys, tokens, test data.
- UUID: Fixed 128-bit format, globally unique. Use for database primary keys, distributed system identifiers.
- Password: Specifically designed for human authentication. Should be hashable, not stored in plaintext.
Generate secure random strings in seconds with our free Random String Generator Tool — customizable length, character sets, and bulk generation.
Conclusion
Generating random strings seems simple, but doing it securely requires understanding the difference between pseudorandom and cryptographically secure randomness, and ensuring sufficient entropy for your use case.
The rules are simple: use a CSPRNG (never Math.random()), choose an appropriate character set, and make the string long enough. When in doubt, 32 bytes of crypto.randomBytes() or secrets.token_urlsafe() will serve you well for virtually any purpose.