Reset Password with Rails

The always brilliant Ryan Bates from Railscasts had a recent episode: #274 Remember Me & Reset Password

I have a slightly different way of handling password resets and thought I’d share.

Ryan walks you through adding two attributes to a User model: password_reset_token and password_reset_sent_at

I am not a fan of adding extra columns to my database tables, especially if only a few records will use it temporarily.

If you follow along with episode #250 Authentication From Scratch , you should have two columns: an encrypted password column password_hash, and the salt password_salt.

What I do differently is use ActiveSupport::MessageVerifier to create self-expiring, encrypted tokens for password resets.

I encrypt a date in the future using the user’s current hashed password as the salt.

I then append the encrypted date string to the end of the user’s id and encrypt that using the secret_token that Rails generates on app creation (in config/initializers/secret_token.rb).

In the User model, I add two methods to do this:

  def generate_token
    ActiveSupport::MessageVerifier.new(Rails.configuration.secret_token).generate([id, 1.day.from_now, password_digest])
  end

  def self.find_by_token(token)
    begin
      user_id, expiration = ActiveSupport::MessageVerifier.new(Rails.configuration.secret_token).verify(token)
      if expiration.future?
        Member.find(user_id)
      end
    rescue
      nil
    end
  end

Example:

the_user = User.first
reset_token = the_user.generate_token
# Mail reset_token to the_user

# … verify token and reset password:

if the_user = User.find_by_token(reset_token)
  # reset_token is valid, OK to change password
  the_user.password = new_password
end

Pros:

  • No extra, unused columns in your database tables.
  • An attacker needs two keys ( user’s password digest and your apps secret_token) to compromise a user account.
  • Once a password is changed on a user account, all tokens for that user are immediately invalid

Con:

  • If an attacker gains access to a copy of your users table and codebase you’ll have to regenerate your secret_token to prevent them from being able to reset *all* the user passwords

Leave a Reply

Your email address will not be published. Required fields are marked *