0

I am trying to configure token generation with devise in a grape api rails app. Since I have the current version of devise, token generation has been disabled. I am having several issues. First, is that when I submit a username and password to the sessions controller, it gives me an error that "ensure_authentication_token":

undefined method `ensure_authentication_token!' for #<User:0x007f880cca9090>

This is so strange because as you can see below, I have it defined in my user model and when I manually create Users in rails console, it works properly.

Is that a scope issue or why is that occurring?

User Model:

class User < ActiveRecord::Base
  before_save :ensure_authentication_token
  # Include default devise modules. Others available are:
  # :confirmable, :lockable, :timeoutable and :omniauthable
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :trackable, :validatable


  def ensure_authentication_token
    if authentication_token.blank?
      self.authentication_token = generate_authentication_token
    end
  end

  private

    def generate_authentication_token
      loop do
        token = Devise.friendly_token
        break token unless User.where(authentication_token: token).first
      end
    end
end

Sessions Grape API Controller:

module API
  module V1
    class Sessions < Grape::API
      include API::V1::Defaults

      resource :sessions do

        params do
          requires :email, type: String, desc: "Email"
          requires :password, type: String, desc: "Password"
        end

       post do
         email = params[:email]
         password = params[:password]

         if email.nil? or password.nil?
           error!({error_code: 404, error_message: "Invalid Email or Password."},401)
           return
         end

         user = User.where(email: email.downcase).first
         if user.nil?
           error!({error_code: 404, error_message: "Invalid Email or Password."},401)
           return
         end

         if !user.valid_password?(password)
           error!({error_code: 404, error_message: "Invalid Email or Password."},401)
           return
         else
           user.ensure_authentication_token!
           user.save
           {status: 'ok', token: user.authentication_token}.to_json
         end
       end
      end
    end
  end
end

The second problem is that when I follow this blog, it says that I need to add the following authentication check in my defaults.rb in the base api controller. When I add the "before do" section, I get access denied error even if I enter in the right credentials and it doesn't even go on to the rest of the sessions controller that I mentioned above.

before do
    error!("401 Unauthorized, 401") unless authenticated
  end

  helpers do
    def warden
      env['warden']
    end

    def authenticated
      return true if warden.authenticated?
      params[:access_token] && @user = User.find_by_authentication_token(params[:access_token])
    end

    def current_user
      warden.user || @user
    end
  end

Thanks for any help you can give!

EDIT: Phillip was absolutely correct that one of these issues was due to the bang versus non banged version of ensure_authentication_token. Removing the ! from the controller fixed that issue. The other problem was indeed from adding the "before do" loop I had.

This is so close to working, I can give and receive tokens in my api but when it connects to ember, it complains about a lack of a csrf token even though I have "protect_from_forgery with: :null_session" set in my application.rb

Coherent
  • 1,933
  • 5
  • 24
  • 33
  • 1
    You can't call that before block all the time since it will block the authentication api call you're trying to make in the first place. – Philip Hallstrom Feb 11 '15 at 23:13
  • 1
    Did you make a typo or is it complaining about `ensure_authentication_token!` when you have defined `ensure_authentication_token` (bang vs non bang methods)? – Philip Hallstrom Feb 11 '15 at 23:52

1 Answers1

2

In your User model, you define a method called ensure_authentication_token.

In your Session controller, you call a method called ensure_authentication_token!.

These are not the same method: Why are exclamation marks used in Ruby methods?

This is preventing you from generating an authentication token, which probably explains the "401 Unauthorized, 401" error.

Community
  • 1
  • 1
Jake Worth
  • 5,490
  • 1
  • 25
  • 35
  • Thanks for the response! So in this case, I'd probably want the non bang/! version for all cases, right? – Coherent Feb 12 '15 at 05:57
  • 1
    Either one is fine, they just have to be the same. Since there is no bang in the method, I'd go with no bang. You are saving the record on the next line of the controller anyway, which is what the bang means to Devise. More info: http://ruby-doc.org//gems/docs/d/dcu-devise-1.0.7/Devise/Models/TokenAuthenticatable.html – Jake Worth Feb 12 '15 at 14:50