Nepal on Rails

millisami's rants!

Simple Custom Authentication for App That Uses Devise

The application I’m working can have many api keys. So, the authentication has been done via the api key itself.

But to ease the CLI, the cli command has to get the default api key via REST Api with the command like my_app_cli login and the user has to provide the email and password.

Now, it was a bit painful to authenticate the Devise way since the web interface authentication uses it.

I had to hack the devise controller and configs to get it working. Though I nailed down the authentication via cli, I was not happy enough with the session being opened via Devise to just get the default api key only once.

So later I dug around the Devise and got this simple authentication working without any hassle, opening session and touching the devise layer.

This is the part of the spec:

# spec/api/v1/account_spec.rb
...
post "/api/v1/account_login.json", :user => {:email => "john@doe.com", :password => "secret"}
last_response.status.should eql(200)
...

And this is the implementation:

# app/controllers/api/v1/accounts_controller.rb
class Api::V1::AccountsController < Api::V1::BaseController

  def login
    user = User.where(:email => params[:user][:email]).first
    if user.present?
      if ::BCrypt::Password.new(user.encrypted_password) == "#{params[:user][:password]}#{Devise.pepper}"
        render :status => 200, :json => { :api_key => user.account.apps.first.key }
      else
        render_error
      end
    else
      render_error
    end
  end

  private
  def render_error
    render :status => 401, :json => {:error => {:message => "Invalid credential."}}
  end
end

The real meat is just this line that is used by Devise to do database authentication.

if ::BCrypt::Password.new(user.encrypted_password) == "#{params[:user][:password]}#{Devise.pepper}"

Hope somebody might find this helpful in, obviously, future!