Try it yourself with our free Password Generator tool — runs entirely in your browser, no signup needed.

How to Generate secure passwords in Ruby

How to generate secure passwords in Ruby

Generating secure passwords is a crucial task in many applications, especially those that require user authentication. A secure password is one that is difficult for attackers to guess or crack, and Ruby provides several ways to generate such passwords. In this guide, we will explore how to generate secure passwords in Ruby using the securerandom library, which is part of the Ruby Standard Library.

Quick Example

require 'securerandom'

def generate_password(length = 12)
  characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'
  SecureRandom.hex(length / 2).scan(/../).map do |pair|
    characters[("0x#{pair}".to_i(16) % characters.size)]
  end.join
end

puts generate_password(12) # Output: a random password of length 12

This code generates a random password of the specified length (defaulting to 12) using a combination of uppercase and lowercase letters, and numbers.

Step-by-Step Breakdown

Let's walk through the code line by line:

  1. require 'securerandom': We require the securerandom library, which provides a cryptographically secure pseudo-random number generator.
  2. def generate_password(length = 12): We define a method generate_password that takes an optional length parameter, defaulting to 12.
  3. characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789': We define a string of all possible characters that can be used in the password.
  4. SecureRandom.hex(length / 2): We use SecureRandom.hex to generate a cryptographically secure random hexadecimal string of length length / 2. We divide by 2 because each hexadecimal character represents 4 bits, so we need half as many characters to represent the desired length.
  5. scan(/../): We split the hexadecimal string into pairs of characters using the scan method.
  6. map do |pair|: We iterate over each pair of characters.
  7. characters[("0x#{pair}".to_i(16) % characters.size)]: We convert each pair of characters to an integer using the to_i method with base 16, and then use the modulo operator to ensure the index is within the bounds of the characters string. We then use this index to select a character from the characters string.
  8. join: We join the resulting characters into a single string.
  9. puts generate_password(12): We call the generate_password method with a length of 12 and print the resulting password.

Handling Edge Cases

Empty/null input

If the input length is empty or null, we can add a simple check to raise an error:

def generate_password(length = 12)
  raise ArgumentError, 'Length must be a positive integer' if length.nil? || length <= 0
  # ... rest of the code ...
end

Invalid input

If the input length is not an integer, we can add a check to raise an error:

def generate_password(length = 12)
  raise ArgumentError, 'Length must be an integer' unless length.is_a?(Integer)
  # ... rest of the code ...
end

Large input

If the input length is very large, the SecureRandom.hex method may take a long time to generate the random string. In this case, we can use a different approach, such as generating the password in chunks:

def generate_password(length = 12)
  password = ''
  while password.size < length
    password += SecureRandom.hex(16)
  end
  password[0, length]
end

Unicode/special characters

If we want to include Unicode or special characters in the password, we can add them to the characters string:

characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()_+-={}:<>?'

Common Mistakes

Using a non-cryptographically secure random number generator

# Wrong
password = (0...length).map { (65 + rand(26)).chr }.join
# Correct
password = SecureRandom.hex(length / 2).scan(/../).map do |pair|
  characters[("0x#{pair}".to_i(16) % characters.size)]
end.join

Not checking for invalid input

# Wrong
def generate_password(length)
  # ... rest of the code ...
end
# Correct
def generate_password(length = 12)
  raise ArgumentError, 'Length must be a positive integer' if length.nil? || length <= 0
  # ... rest of the code ...
end

Not handling edge cases

# Wrong
def generate_password(length = 12)
  # ... rest of the code ...
end
# Correct
def generate_password(length = 12)
  raise ArgumentError, 'Length must be a positive integer' if length.nil? || length <= 0
  # ... rest of the code ...
end

Performance Tips

Use SecureRandom.hex instead of SecureRandom.random_number

SecureRandom.hex is faster and more efficient than SecureRandom.random_number because it generates a hexadecimal string directly, rather than generating a random number and then converting it to a string.

Use a larger characters string

Using a larger characters string can increase the entropy of the generated password, making it more secure.

Avoid generating very large passwords

Generating very large passwords can take a long time and may not be necessary for most use cases.

FAQ

Q: What is the minimum length of a secure password?

A: The minimum length of a secure password is generally considered to be 12 characters.

Q: Can I use this method to generate passwords for other applications?

A: Yes, this method can be used to generate passwords for other applications, but you should consider the specific requirements and constraints of each application.

Q: How do I store the generated password securely?

A: The generated password should be stored securely using a password hashing algorithm, such as bcrypt or PBKDF2.

Q: Can I use this method to generate passwords for humans to remember?

A: No, this method generates random passwords that are not suitable for humans to remember. For human-readable passwords, consider using a password generator that generates pronounceable passwords.

Q: Is this method compatible with all Ruby versions?

A: This method is compatible with Ruby 1.9.3 and later.

AI agent tools available. The CodeTidy MCP Server gives Claude, Cursor, and other AI agents access to 60+ developer tools. One command: npx @codetidy/mcp