Creating “Forgot password” feature on Rails API

Pascales Kurniawan
Binar Academy
Published in
2 min readJun 19, 2018

Just a small note for myself…

Hello, today I want to share about common feature that always can be found on a login page, a “Forgot password” feature. The flow is simple, user that forgot his password clicks the “forgot password” link, then the user should input email address he was registered with. After that a token is sent to the email address. User then sends the token along with the new password, after it is successfuly sent, the password then resetted.

okay, first thing first, let’s generate migration to add reset_password_token and reset_password_sent_at column to your user table

rails g migration AddPasswordResetColumnsToUser

add_column :users, :reset_password_token, :string
add_column :users, :reset_password_sent_at, :datetime

then we should create password controller for our forgot password methods.

rails g controller passwords

add endpoints for forgot password and reset password in our routes.rb file

config/routes.rb:post 'password/forgot', to: 'password#forgot'
post 'password/reset', to: 'password#reset'

let’s add these codes to our passwords_controller

controllers/passwords_controller.rb:...
def forgot
if params[:email].blank? # check if email is present
return render json: {error: 'Email not present’}
end

user = User.find_by(email: params[:email]) # if present find user by email

if user.present?
user.generate_password_token! #generate pass token
# SEND EMAIL HERE
render json: {status: 'ok’}, status: :ok
else
render json: {error: [’Email address not found. Please check and try again.’]}, status: :not_found
end
end

def reset
token = params[:token].to_s

if params[:email].blank?
return render json: {error: 'Token not present’}
end

user = User.find_by(reset_password_token: token)

if user.present? && user.password_token_valid?
if user.reset_password!(params[:password])
render json: {status: 'ok’}, status: :ok
else
render json: {error: user.errors.full_messages}, status: :unprocessable_entity
end
else
render json: {error: [’Link not valid or expired. Try generating a new link.’]}, status: :not_found
end
end
...

I skip the email generation section, you can find how to send the email on my previous article.

okay, does the codes work ? not yet… let’s add some methods to our user model.

models/user.rb...
def generate_password_token!
self.reset_password_token = generate_token
self.reset_password_sent_at = Time.now.utc
save!
end

def password_token_valid?
(self.reset_password_sent_at + 4.hours) > Time.now.utc
end

def reset_password!(password)
self.reset_password_token = nil
self.password = password
save!
end

private

def generate_token
SecureRandom.hex(10)
end
...

That’s it, you can test it via postman:

If you have any suggestion or correction, please feel free to put it in response bellow, have a nice day….

--

--

Pascales Kurniawan
Binar Academy

"In times of change, learners inherit the earth, while the learned find themselves beautifully equipped to deal with a world that no longer exists."