Featured image

If you work in web development, you’ve almost certainly had to generate random numeric codes like OTPs for logins or transaction verifications sent via SMS or email. It seems like a straightforward task, and your first instinct might be to reach for Kernel#rand. But that method isn’t designed for cryptographically secure random numbers, so the documentation advises switching to a safer alternative: SecureRandom#rand. Next comes requirements that can vary depending on the use case: do all ten digits need to be included in the code, do you need to exclude certain numbers, or do you need to mix in alphanumeric characters.

require 'securerandom'

# fast, but unsafe
rand(0..9999).to_s.rjust(4, '0')
Array.new(4) { rand(10) }.join

# more reliable for the entire range of digits
SecureRandom.rand(0..9999).to_s.rjust(4, '0')
Array.new(4) { SecureRandom.rand(0..9) }.join

# without digits: 0, 1, 5, 6
chars = %w[2 3 4 7 8 9]
SecureRandom.alphanumeric(4, chars:)
Array.new(4) { chars[SecureRandom.rand(chars.length)] }.join
chars.sample(4, random: SecureRandom).join

# explicitly make a system call to the OS
`head -c 4 /dev/random`.bytes.map { _1 % 10  }.join

How do you generate random codes in your projects? Are there other ways you like to handle this cleanly?