Apps Artificial Intelligence CSS DevOps Go JavaScript Laravel Linux MongoDB MySQL PHP Python Rust Svelte Vue

Generate Random Strings in Go

2 min read .
Generate Random Strings in Go

Random strings are useful for temporary identifiers, test data, filenames, invitation codes, and security-sensitive tokens. Go offers different random-number sources, and choosing the correct one matters.

1. math/rand for Non-Security Uses

For simulations, test fixtures, randomized UI behavior, or other cases where predictability is not a security problem, math/rand is appropriate.

With modern Go, create an explicit generator when you need independent pseudo-random state:

package main

import (
	"fmt"
	"math/rand"
)

const alphabet = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"

func GenerateRandomString(r *rand.Rand, length int) string {
	result := make([]byte, length)
	for i := range result {
		result[i] = alphabet[r.Intn(len(alphabet))]
	}
	return string(result)
}

func main() {
	r := rand.New(rand.NewSource(42))
	fmt.Println(GenerateRandomString(r, 10))
}

A fixed seed is useful for reproducible tests. Do not use math/rand for secrets, session tokens, password-reset tokens, or other authentication material.

2. crypto/rand for Security-Sensitive Strings

Use crypto/rand when values must be unpredictable. This implementation selects characters without modulo bias:

package main

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

const alphabet = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"

func GenerateSecureRandomString(length int) (string, error) {
	if length < 0 {
		return "", fmt.Errorf("length must be non-negative")
	}

	result := make([]byte, length)
	max := big.NewInt(int64(len(alphabet)))

	for i := range result {
		n, err := rand.Int(rand.Reader, max)
		if err != nil {
			return "", err
		}
		result[i] = alphabet[n.Int64()]
	}

	return string(result), nil
}

func main() {
	value, err := GenerateSecureRandomString(32)
	if err != nil {
		panic(err)
	}
	fmt.Println(value)
}

For tokens that do not need a custom alphabet, generating random bytes and encoding them is often simpler and faster:

func GenerateToken(byteLength int) (string, error) {
	buf := make([]byte, byteLength)
	if _, err := rand.Read(buf); err != nil {
		return "", err
	}
	return base64.RawURLEncoding.EncodeToString(buf), nil
}

RawURLEncoding is convenient for tokens placed in URLs because it avoids +, /, and padding characters.

3. UUIDs for Standard Identifiers

If you need a conventional unique identifier rather than an arbitrary random string, a UUID can be a good fit:

package main

import (
	"fmt"

	"github.com/google/uuid"
)

func main() {
	id := uuid.New()
	fmt.Println(id.String())
}

UUIDs are common for database identifiers and distributed systems, but they are not automatically a replacement for high-entropy security tokens.

Which Option Should You Use?

Method Good for Avoid for
math/rand simulations, tests, non-secret randomization authentication and secrets
crypto/rand tokens, reset links, secret identifiers cases that need deterministic output
UUID standardized unique identifiers arbitrary-format secret tokens

Conclusion

Use math/rand when reproducibility or lightweight pseudo-randomness is enough. Use crypto/rand whenever unpredictability is part of the security requirement. Use UUIDs when you need a standardized identifier format rather than a general-purpose random string.

Related Posts

chevron-up