Search code examples
ruby-on-railsdevisedevise-recoverable

Sending unhashed Devise reset_password_token in custom email


I'm using Devise 3.5 in my Rails 4.2 app. I've overridden all of the stock emails with custom HTML emails. Because of how I've designed the email delivery code, it's impossible for the email templates to have access to the hashed version of a token, such as the reset_password_token.

The problem I'm having is that the email template only has access to the unhashed token that is stored in the database. I've tried using the unhashed token from the database in my email template, but when a user clicks the link, Devise's PasswordsController#update calls resource_class.reset_password_by_token(resource_params). Devise::Recoverable then unhashes the token and tries to find the user. This fails because the unhashed token doesn't match the token in the database (because the token was already unhashed to begin with).

My question is three-part:

  1. What are the security implications of sending the unhashed token in emails such as the password reset email?
  2. I'm assuming that sending the unhashed token is a bad idea. If so, can I get around this problem by overriding PasswordsController#create so that I can intercept the hashed and unhashed tokens and save both to the database, therefore making the hashed token available to my mailer code? Are there security implications I should be aware of before attempting this approach?
  3. Is there some way I can take the unhashed token and hash it before rendering my email template so that I can avoid a hacky workaround such as saving it to the database?

Solution

  • Your assumptions are incorrect. The unhashed token is safe to send in an email, but unsafe to store in the DB. This is so that someone with access to your DB can't reconstruct the password reset URL.

    So you want the email to have access only to the unhashed token.

    For a more detailed discussion, see the "Store digested tokens in the database" at http://blog.plataformatec.com.br/2013/08/devise-3-1-now-with-more-secure-defaults/