Securely handling user passwords is crucial; thankfully, Rails provides a straightforward and powerful method for password management with has_secure_password. This method ensures that passwords are never stored in plain text, making your applications more secure by default.
What is has_secure_password?
The has_secure_password method is part of Rails’ Active Record. It adds a set of features to your model for safely handling user passwords, including hashing and validation. When you use has_secure_password, Rails automatically takes care of storing and verifying passwords in a secure way without requiring any extra setup.
When added to a model (typically a User model), has_secure_password enables the following features:
- Password hashing: The password is never stored as plain text. Instead, Rails uses
bcrypt(by default) to securely hash and store the password in your database. - Password validation: Ensures the password meets certain criteria, such as being at least 6 characters long.
- Password confirmation: Rails also automatically validates that the password and password confirmation fields match.
This method uses bcrypt, a widely used and trusted password hashing algorithm that also adds salt to the password, preventing attackers from using precomputed tables (like rainbow tables) to crack hashed passwords.
How to Use has_secure_password
Using has_secure_password is incredibly simple. Here’s how you can implement it in a User model:
1. Add password_digest column to the database
Before using has_secure_password, ensure your model has a password_digest column. You can create a migration for this:
1
2
rails generate migration AddPasswordDigestToUsers password_digest:string
rails db:migrate
This migration adds the password_digest column to the users table, which will store the hashed password.
2. Use has_secure_password in the User model
Now, in the User model, you simply need to add has_secure_password:
1
2
3
class User < ApplicationRecord
has_secure_password
end
That’s it! Rails will automatically handle password hashing and validation for you.
3. Creating a user with a password
You can now create a user and provide a password in plain text. Rails will hash the password before storing it in the database:
1
user = User.create!(email: "david@example.com", password: "password123", password_confirmation: "password123")
In this example, the password will be securely hashed and stored in the password_digest column.
4. Authenticating a user
To authenticate a user, you can use the authenticate method:
1
2
3
4
5
6
user = User.find_by(email: "david@example.com")
if user.authenticate("password123")
# Authentication successful, user is authenticated
else
# Invalid password
end
The authenticate method compares the plain text password provided ("password123") with the hashed password stored in password_digest. If they match, it returns the user object; otherwise, it returns false.
Password Confirmation
The has_secure_password feature automatically validates that the password and password confirmation match. This helps prevent errors in user input, ensuring that users are providing the same password twice.
1
user = User.create!(email: "john@example.com", password: "secret123", password_confirmation: "secret123")
If the password and password confirmation don’t match, Rails will raise a validation error.
Add a Default Configuration for a 15-Minute Password Reset Token
Another important feature of has_secure_password in Rails is the ability to securely manage password reset tokens. You can set up a configuration for password reset tokens that automatically expires after a set period, such as 15 minutes. This helps prevent unauthorized access by limiting the time window for password reset actions.
1
2
3
4
5
6
7
8
9
user = User.create!(name: "david", password: "123", password_confirmation: "123")
token = user.password_reset_token
User.find_by_password_reset_token(token) # returns user
# 16 minutes later...
User.find_by_password_reset_token(token) # returns nil
# raises ActiveSupport::MessageVerifier::InvalidSignature since the token has expired
User.find_by_password_reset_token!(token)
The has_secure_password method in Rails simplifies the process of securely managing user passwords. It handles password hashing and validation automatically, using bcrypt to ensure that passwords are stored safely. It also provides built-in password confirmation, validation, and authentication methods, making it an excellent choice for most applications.