Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Q: current_user is not set #86

Closed
killerham opened this issue Aug 9, 2014 · 11 comments
Closed

Q: current_user is not set #86

killerham opened this issue Aug 9, 2014 · 11 comments
Labels
question When closed, this issue will become part of the FAQ.

Comments

@killerham
Copy link

My Api is returning nil for current_user when I pass email and token through the header. My session controller sees current_user when creating and destroying a new session.

module Api
  module V1

    class UsersController < Api::V1::ApplicationController

      include Devise::Controllers::Helpers

      acts_as_token_authentication_handler_for User, fallback_to_devise: false

      def index

        render json: {
                     success: true,
                     auth_token: current_user.authentication_token,
                     email: current_user.email
                   }

      end

    end

  end
end
@killerham
Copy link
Author

Another question I have is what is a good way of just checking if the token is still good? Basically, I just wanted to sign in with a token and check if it returns back a user which is why I have my index returning current_user if they are signed in.

@gonzalo-bulnes
Copy link
Owner

Hi @killerham,

I'm not sure to understand your first question, but since it has to do with current_user, which is a Devise method, I would check first if Devise is correctly installed.
Please take a look at #42, even if the error is not exactly the same, it may well have the same cause.

On how you can look at the authentication tokens, you can is to inspect the records from a Rails console:

rails console
2.1.1 :001 > User.all.map{|user| {id: user.id, authentication_token: user.authentication_token} }
# User Load (1.7ms)  SELECT "users".* FROM "users"
# => [{:id=>1, :authentication_token=>"cr7JqW-_asasdfeapRh"},
#     {:id=>3, :authentication_token=>"wmvRmm-5pi9c2kGQm3NW"},
#     {:id=>2, :authentication_token=>"rMKz3mflfapBfGS4MtaDQ"}] 

@killerham
Copy link
Author

Whoops, forgot to reply. It was because I was using the API controller. The issue/branch from here: #54 fixed my issue.

@gonzalo-bulnes
Copy link
Owner

Ok @killerham, thanks for your feedback!

@gonzalo-bulnes gonzalo-bulnes added the question When closed, this issue will become part of the FAQ. label Nov 17, 2014
@gonzalo-bulnes gonzalo-bulnes changed the title current_user is nil Q: current_user is not set Nov 17, 2014
@gonzalo-bulnes
Copy link
Owner

@feliperaul wrote in #188:

[...] I'm having issues. Take a look at my example controller:

class DashboardController < ApplicationController
  layout 'new'
  acts_as_token_authentication_handler_for User, fallback: :devise  
def index 
....

If I try to access /dashboard without the token params, it prompts me for password just like before, which shows that devise fallback is being triggered (I guess).

But if I pass the params in the URL, like /dashboard?user_email=user@app.com&user_token=GNHuhDQzhYmYyszdYZEx, it starts rendering all sorts of weird errors, like undefined method each_with_index' for nil:NilClass`in a line that has the following code (the line lives in the layout template):

<% @last_contacts.each_with_index do |contact, index| %>

This instance variable @last_contacts is generated from a method that is inside ApplicationController, from which, as you saw above, DashboardController derives from:

class ApplicationController < ActionController::Base
  protect_from_forgery
  before_filter :set_locale
  before_filter :set_authorization_user
  layout 'omega'
  before_filter :redirect_to_http
  before_filter :populate_last_contacts_for_menu 
private
  def populate_last_contacts_for_menu
      @last_contacts = Contact.where("user_id" => current_user.id).where('blocked != ? or blocked is null', true).last(10).reverse
  end

Sorry for pasting all this code, but if I remove the @last_contacts loop from the layout, the authentication works fine. This should be an issue tough, since I shouldn't have to modify my views and layouts just for authentication to work properly if with Devise this was not being required.

My versions;
simple_token_authentication (1.10.1)
devise (3.4.1) (which as far as I can see in the gemfile.lock is higher then the dependency).


@gonzalo-bulnes The exception is happening because current_user is not set. I read #86 but it didn't help.

I can log in with Devise fine, it's a Rails app running in production for more then one year.


@gonzalo-bulnes
Just a followup (because I think as the gem curator you are interested in knowing bugs that happen :)

My colleague, checking out at the exactly same branch as I am, is not even being able to try to debug our issue.

As soon as he tries to open any view, he gets an exception from within a view that is deprecated and shouldn't even be called.

This is so bizarre I had him to open a VNC session with me so I could believe he was not on a different branch.

--- Edit: this was our fault. We were actually using 2 different controllers, and one of the controllers had fallback: none and didn't call Devise.

Anyways, the bug persists: current_user is defined within the Dashboard Controller and also it's layout, but inside ApplicationController it is nil!


Update: this might be related (I know it's another gem, but it's a gem that supposedly does that same as this without being simple at all), but I still couldn't solve it (I tried setting devise_for :users) outside any scope in routes.rb

lynndylanhurley/devise_token_auth#28

@gonzalo-bulnes
Copy link
Owner

Hi @feliperaul,

If I try to access /dashboard without the token params, it prompts me for password just like before, which shows that devise fallback is being triggered (I guess).

Yes, that's right.

But if I pass the params in the URL, like /dashboard?user_email=user@app.com&user_token=GNHuhDQzhYmYyszdYZEx, it starts rendering all sorts of weird errors, like undefined methodeach_with_index' for nil:NilClass` in a line [...]

As you noticed, the errors are a consequence of current_user being nil in the line in question, that makes perfect sense to me. Let's check why current_user could be nil:

  1. Is Devise correctly intalled? Yes, because current_user is defined.
  2. Are the user token authentication credentials present? Yes, and when they are missing the fallback is triggered as expected.
  3. Are the user credentials correct? They seems to be correct, because if they were not the fallback would be triggered and Devise would ask for correct credentials.

[...] if I remove the @last_contacts loop from the layout, the authentication works fine

Do you mean if you remove the reference to current_user from ApplicationController#populate_last_contacts_for_menu the user gets successfully token authenticated?To me, that means current_user is not being set, which contradicts point 3. above.

Just to cross-check that, I could you raise current_user in DashboardController#index please?
If current_user is correctly set in DashboardController#index, can you inspect it in ApplicationController#populate_last_contacts_for_menu?

It doesn't make sense to me that current_user could be available in #index but not in #populate_last_contacts_for_menu. Both methods are defined in different classes, but since DashboardController inherits from ApplicationController, both are instance methods of your controller. I think current_user isn't set at all (and -I'm thinking aloud- maybe the successful authentication when you remove the @last_contacts-related code is a cache effect - remember your session is persisted).

If current_user is not set at all, despite the correct credentials, then 1. it's a good news because that's what I would expect 2. I would ask: may the :set_authorization_user affect current_user in any way? Oh, no, I think I know what's happening! The populate_last_contacts_for_menu callback is defined in the ApplicationController, that's to say before the Simple Token Authentication callbacks (which are defined by acts_as_token_authentication_hanlder). So the #populate_last_contacts_for_menu method gets called before current_user is set : ) - and that may explain why current_user seems to be set when you remove the :populate_last_contacts_for_menu callback: because the error doesn't occur anymore, the authentication is performed and current_user is set! :D

Try moving the before :populate_last_contacts_for_menu statement after acts_as_token_authentication_handler [...] please, just to check if I'm right. I can then help you finding a way not to repeat it in all your controllers...

@gonzalo-bulnes
Copy link
Owner

By the way, I think it's more than worth re-opening this issue!

@feliperaul
Copy link

@gonzalo-bulnes Taking a look at it !

@jamesfzhang
Copy link

I don't know if I am experiencing the same issue, but I am seeing inconsistent results with current_user. In debugging, I tried logging in & out 10 times without changing the code and sometimes I have a current_user, other times its nil. So bizarre.

My controller has endpoints for 1). checking the existence of a current_user, 2). logging in, and 3). logging out

class Api::V2::SessionsController < Devise::SessionsController
  acts_as_token_authentication_handler_for User
  skip_before_filter :verify_authenticity_token, only: [:create, :destroy]
  skip_filter :verify_signed_out_user, only: [:destroy]
  respond_to :json

  def index
    if current_user
      render json: { logged_in: true, user: current_user }
    else
      render json: { logged_in: false }
    end
  end

  def create
    self.resource = warden.authenticate!(auth_options)
    if sign_in(resource_name, resource)
      render json: current_user
    else
      render json: {}, status: 400
    end
  end

  def destroy
    if current_user
      current_user.update authentication_token: nil
      signed_out = Devise.sign_out_all_scopes ? sign_out : sign_out(resource_name)
      render json: { logged_out: true }
    else
      render json: {}, status: 403
    end
  end
end

On the client side, on page load, I call api/v2/sessions.json to check for the existence of a current_user, SOMETIMES its nil, other times it returns the correct user. I've verified that the correct headers are present. Any ideas?

@jamesfzhang
Copy link

So, it turns out that I was storing the user ID (I use ID instead of email) & auth token in the cookie and i didn't namespace the keys (just userID and authenticationToken) so there was another cookie using the same name userID key, which caused the WRONG header values to be sent to the server. I can't explain why it worked sometimes and not others (reading the cookie shouldn't be probabilistic), but now that I've namespaced my cookie keys, this is no longer a problem for me.

@gonzalo-bulnes
Copy link
Owner

Oh, that's very good to keep an eye on. Thank you for sharing @jamesfzhang.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question When closed, this issue will become part of the FAQ.
Projects
None yet
Development

No branches or pull requests

4 participants