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
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.