Secure Random String Generator in Every Programming Language

Published March 9, 2026 · 10 min read

Every programming language has a way to generate cryptographically secure random strings, but the API differs wildly between languages. This is your copy-paste reference for generating secure API keys, tokens, and secrets in JavaScript, Python, Go, Rust, Java, C#, Ruby, PHP, Swift, and Kotlin.

Every example below uses a CSPRNG (Cryptographically Secure Pseudo-Random Number Generator) that draws from the operating system's entropy pool. None of them use insecure sources like Math.random(), rand(), or Random().

Quick Reference Table

LanguageCSPRNG SourceModule/Import
JavaScriptcrypto.getRandomValues()Built-in (Web Crypto API)
Node.jscrypto.randomBytes()node:crypto
Pythonsecrets.token_hex()secrets (stdlib)
Gocrypto/rand.Read()crypto/rand
RustOsRngrand crate
JavaSecureRandomjava.security
C#RandomNumberGeneratorSystem.Security.Cryptography
RubySecureRandomsecurerandom (stdlib)
PHPrandom_bytes()Built-in (PHP 7+)
SwiftSecRandomCopyBytesSecurity framework
KotlinSecureRandomjava.security

JavaScript (Browser)

function secureRandomString(length = 32) {
  const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
  const bytes = new Uint8Array(length);
  crypto.getRandomValues(bytes);
  return Array.from(bytes, b => chars[b % chars.length]).join('');
}

// Hex variant
function secureRandomHex(bytes = 32) {
  const buf = new Uint8Array(bytes);
  crypto.getRandomValues(buf);
  return Array.from(buf, b => b.toString(16).padStart(2, '0')).join('');
}

console.log(secureRandomString());    // "Kx9mR4vL2bN7qP5sT8wJ1cF6gH0iA3d"
console.log(secureRandomHex());       // "a3f8c1d9e4b7..."

Node.js

import { randomBytes } from 'node:crypto';

// Hex string
function secureRandomHex(bytes = 32) {
  return randomBytes(bytes).toString('hex');
}

// Base64URL string
function secureRandomBase64URL(bytes = 32) {
  return randomBytes(bytes).toString('base64url');
}

// Alphanumeric string
function secureRandomAlphanumeric(length = 32) {
  const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
  const bytes = randomBytes(length);
  return Array.from(bytes, b => chars[b % chars.length]).join('');
}

console.log(secureRandomHex());          // 64-char hex string
console.log(secureRandomBase64URL());    // 43-char base64url string
console.log(secureRandomAlphanumeric()); // 32-char alphanumeric string

Python

import secrets
import string

# Hex string (simplest)
token = secrets.token_hex(32)  # 64-char hex, 256 bits

# URL-safe Base64 string
token = secrets.token_urlsafe(32)  # 43-char base64url, 256 bits

# Alphanumeric string
def secure_random_string(length=32):
    alphabet = string.ascii_letters + string.digits
    return ''.join(secrets.choice(alphabet) for _ in range(length))

print(secure_random_string())  # "Kx9mR4vL2bN7qP5sT8wJ1cF6gH0iA3d"

Always use the secrets module in Python, never random. The random module uses a Mersenne Twister PRNG which is predictable and unsuitable for security.

Go

package main

import (
    "crypto/rand"
    "encoding/hex"
    "fmt"
    "math/big"
)

// Hex string
func secureRandomHex(byteLen int) string {
    b := make([]byte, byteLen)
    if _, err := rand.Read(b); err != nil {
        panic(err)
    }
    return hex.EncodeToString(b)
}

// Alphanumeric string
func secureRandomString(length int) string {
    const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
    result := make([]byte, length)
    for i := range result {
        n, _ := rand.Int(rand.Reader, big.NewInt(int64(len(chars))))
        result[i] = chars[n.Int64()]
    }
    return string(result)
}

func main() {
    fmt.Println(secureRandomHex(32))     // 64-char hex
    fmt.Println(secureRandomString(32))  // 32-char alphanumeric
}

Go's crypto/rand reads from /dev/urandom on Unix and CryptGenRandom on Windows. Never use math/rand for security-sensitive operations — it is seeded with a predictable value.

Rust

use rand::Rng;
use rand::rngs::OsRng;

fn secure_random_hex(byte_len: usize) -> String {
    let mut bytes = vec![0u8; byte_len];
    OsRng.fill(&mut bytes[..]);
    hex::encode(bytes)
}

fn secure_random_string(length: usize) -> String {
    const CHARS: &[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
    let mut rng = OsRng;
    (0..length)
        .map(|_| {
            let idx = rng.gen_range(0..CHARS.len());
            CHARS[idx] as char
        })
        .collect()
}

fn main() {
    println!("{}", secure_random_hex(32));
    println!("{}", secure_random_string(32));
}

Add these to your Cargo.toml:

[dependencies]
rand = "0.8"
hex = "0.4"

Java

import java.security.SecureRandom;
import java.util.Base64;

public class SecureRandomGenerator {
    private static final SecureRandom random = new SecureRandom();
    private static final String CHARS =
        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";

    // Hex string
    public static String randomHex(int byteLength) {
        byte[] bytes = new byte[byteLength];
        random.nextBytes(bytes);
        StringBuilder sb = new StringBuilder(byteLength * 2);
        for (byte b : bytes) {
            sb.append(String.format("%02x", b));
        }
        return sb.toString();
    }

    // Alphanumeric string
    public static String randomString(int length) {
        StringBuilder sb = new StringBuilder(length);
        for (int i = 0; i < length; i++) {
            sb.append(CHARS.charAt(random.nextInt(CHARS.length())));
        }
        return sb.toString();
    }

    // Base64URL string
    public static String randomBase64URL(int byteLength) {
        byte[] bytes = new byte[byteLength];
        random.nextBytes(bytes);
        return Base64.getUrlEncoder().withoutPadding().encodeToString(bytes);
    }
}

Java's SecureRandom automatically selects the best available CSPRNG for the platform. On Linux, it uses /dev/urandom by default.

C# / .NET

using System.Security.Cryptography;

// .NET 6+ (recommended)
static string SecureRandomHex(int byteLength = 32)
{
    byte[] bytes = RandomNumberGenerator.GetBytes(byteLength);
    return Convert.ToHexString(bytes).ToLower();
}

static string SecureRandomString(int length = 32)
{
    const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
    byte[] bytes = RandomNumberGenerator.GetBytes(length);
    char[] result = new char[length];
    for (int i = 0; i < length; i++)
    {
        result[i] = chars[bytes[i] % chars.Length];
    }
    return new string(result);
}

static string SecureRandomBase64URL(int byteLength = 32)
{
    byte[] bytes = RandomNumberGenerator.GetBytes(byteLength);
    return Convert.ToBase64String(bytes)
        .Replace('+', '-')
        .Replace('/', '_')
        .TrimEnd('=');
}

Ruby

require 'securerandom'

# Hex string
token = SecureRandom.hex(32)  # 64-char hex, 256 bits

# Base64URL string
token = SecureRandom.urlsafe_base64(32)  # 43-char base64url

# Alphanumeric string
def secure_random_string(length = 32)
  chars = [*'A'..'Z', *'a'..'z', *'0'..'9']
  Array.new(length) { chars.sample(random: SecureRandom) }.join
end

puts secure_random_string  # "Kx9mR4vL2bN7qP5sT8wJ1cF6gH0iA3d"

PHP

<?php
// Hex string (PHP 7+)
$token = bin2hex(random_bytes(32));  // 64-char hex, 256 bits

// Alphanumeric string
function secureRandomString(int $length = 32): string {
    $chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
    $result = '';
    $bytes = random_bytes($length);
    for ($i = 0; $i < $length; $i++) {
        $result .= $chars[ord($bytes[$i]) % strlen($chars)];
    }
    return $result;
}

// Base64URL string
function secureRandomBase64URL(int $byteLength = 32): string {
    return rtrim(strtr(base64_encode(random_bytes($byteLength)), '+/', '-_'), '=');
}

echo secureRandomString();  // "Kx9mR4vL2bN7qP5sT8wJ1cF6gH0iA3d"

PHP's random_bytes() (PHP 7+) and random_int() use the OS CSPRNG. Never use mt_rand(), rand(), or uniqid() for security-sensitive strings.

Swift

import Foundation
import Security

func secureRandomHex(byteLength: Int = 32) -> String {
    var bytes = [UInt8](repeating: 0, count: byteLength)
    let status = SecRandomCopyBytes(kSecRandomDefault, byteLength, &bytes)
    guard status == errSecSuccess else { fatalError("CSPRNG failed") }
    return bytes.map { String(format: "%02x", $0) }.joined()
}

func secureRandomString(length: Int = 32) -> String {
    let chars = Array("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789")
    var bytes = [UInt8](repeating: 0, count: length)
    SecRandomCopyBytes(kSecRandomDefault, length, &bytes)
    return String(bytes.map { chars[Int($0) % chars.count] })
}

print(secureRandomHex())     // 64-char hex
print(secureRandomString())  // 32-char alphanumeric

Kotlin

import java.security.SecureRandom

fun secureRandomHex(byteLength: Int = 32): String {
    val bytes = ByteArray(byteLength)
    SecureRandom().nextBytes(bytes)
    return bytes.joinToString("") { "%02x".format(it) }
}

fun secureRandomString(length: Int = 32): String {
    val chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
    val random = SecureRandom()
    return (1..length)
        .map { chars[random.nextInt(chars.length)] }
        .joinToString("")
}

fun main() {
    println(secureRandomHex())     // 64-char hex
    println(secureRandomString())  // 32-char alphanumeric
}

Common Pitfalls Across All Languages

  1. Using the wrong random source. Every language has both a fast-but-insecure PRNG and a slower-but-secure CSPRNG. Use the CSPRNG for any security-sensitive operation.
  2. Modulo bias. Using byte % charset_length introduces slight bias when 256 is not evenly divisible by the charset length. For most API key use cases (charset of 62), the bias is negligible (< 0.4%). For maximum uniformity, use rejection sampling.
  3. Insufficient length. Generate at least 16 bytes (128 bits of entropy) for any token used in production. 32 bytes (256 bits) is recommended.
  4. Logging the full key. Log only a prefix (first 4-8 characters) for debugging. Never log the complete key.
  5. Storing keys in plaintext. Hash keys with SHA-256 before storing in a database. Show the full key to the user exactly once at creation time.

Need a quick key without writing code? Use our free API key generator which supports hex, base64, base64url, alphanumeric, and prefixed formats.

Recommended Resources

For the cryptographic foundations behind every CSPRNG in this article, read Real-World Cryptography. It covers how entropy pools, PRNGs, and secure random generation work across operating systems.

For JavaScript-specific depth, JavaScript: The Definitive Guide is the standard reference. To understand how weak random generation gets exploited, The Web Application Hacker's Handbook covers real attack scenarios.

SPUNK LLC Network

API Sites

Key Management

More from SPUNK LLC