3
votes

I am using devise gem. Devise send reset password token in mail when user clicks on forget password link. User follow the link and reset his password by entering new password and confirm new password.

When I follow the same mail link again, it again allow the user to reset password in the same way as above.

Now, I want the reset password token to clear once it is used. So that when your follow the previously used send link from old mail, he must get message that "Invalid token"

How can I do this?

Thanks in advance.

4
Which version of Rails and devise are you using ?Arihant Godha
Rails 3.2.13 Devise 3.1.0Ketan Ghumatkar

4 Answers

2
votes

Easier and safer solution than what was proposed:

Create your own passwords controller, I chose to place it under controllers/auth

controllers/auth/passwords_controller.rb

class Auth::PasswordsController < Devise::PasswordsController

  def update
    super do |resource|
      if resource.reset_password_token_changed? and resource.reset_password_token_was.nil?
        resource.reset_password_token = nil 
      end
    end
  end

end

This fix many problem with papertrail for example, and anyhow save one access to the DB

0
votes

You can try either of the following methods

 # reset_password_within = 1.day and reset_password_sent_at = today
reset_password_period_valid?   # returns true

# reset_password_within = 5.days and reset_password_sent_at = 4.days.ago
reset_password_period_valid?   # returns true

# reset_password_within = 5.days and reset_password_sent_at = 5.days.ago
reset_password_period_valid?   # returns false

# reset_password_within = 0.days
reset_password_period_valid?   # will always return false

or you can call the instance methods like clear reset password token or by calling clear_reset_password_token or after_password_reset methods.

0
votes

I think this hack should be more easier if you do the following in your user model or the model that has been used by devise.

class YourModel < ActiveRecord::Base
  ...
     def after_password_reset
          self.clear_reset_password_token if not (self.reset_password_token.nil? and self.reset_password_sent_at.nil?)
     end
end

I suggest not to use your controller to perform business operation. This after_password_reset password is used to called after clear_reset_password token in devise. Here is the reference: https://github.com/plataformatec/devise/blob/master/lib/devise/models/recoverable.rb#L39

Hope this will help.

-1
votes

I have achieved above by overriding Devise::PasswordsController in application.

Devise handle reset password on PasswordController#edit action.

On edit, I have checked if the reset password token is valid or not. If its valid I allow user to reset password otherwise redirect user to sign in page with "Password token is invalid message".

For devise 3.0

class Users::PasswordsController < Devise::PasswordsController
  def edit
    self.resource = resource_class.find_or_initialize_with_error_by(:reset_password_token,       params[:reset_password_token])
    if !resource.errors.empty?
      flash[:alert] = "Password token is invalid"
      redirect_to new_session_path(resource_name)
    end 
  end
end

For devise 3.1

class Users::PasswordsController < Devise::PasswordsController
  def edit
    original_token       = params[:reset_password_token]
    reset_password_token = Devise.token_generator.digest(self, :reset_password_token, original_token)
    self.resource = resource_class.find_or_initialize_with_error_by(:reset_password_token, reset_password_token)
    if !resource.errors.empty?
      flash[:alert] = "Password token is invalid"
      redirect_to new_session_path(resource_name)
    end
  end
end