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

Having both devise and devise_token_auth #120

Closed
casertap opened this issue Jan 26, 2015 · 20 comments
Closed

Having both devise and devise_token_auth #120

casertap opened this issue Jan 26, 2015 · 20 comments

Comments

@casertap
Copy link

I have a lot of trouble to set up my application with both devise and devise_token_auth.
We are slowly migrating from a rails server-side rendering to an angularjs application.
The problem is that I want to have a way to log in and have part of my website with angular and part without angular (yet).
It seems that with devise_token_auth the current_user is not statefull, that is a problem for me because I need to log in ones and then I just need to check if current_user exists.
At least I need to do that until the migration is complete and I can totally switch to a token auth.
Do you have an idea on how to solve my problem?

@lynndylanhurley
Copy link
Owner

I'm having a hard time understanding this issue. Can you please elaborate? For example, what do you mean by "stateful"?

Also, have you read this section of the README?

@casertap
Copy link
Author

casertap commented Feb 9, 2015

Ok I will try to be more clear.
I actually have an application that use Devise to loggin/signin etc...
So when I currently loggin, a new current_user is created and then I keep this user until he logout.

We are migrating page after page to angularJS so I was wondering if it is possible to have devise_token_auth on pages with angular and my standard Devise for my old pages.
The thing is that I only want an unique way to loggin.

@nickL
Copy link
Contributor

nickL commented Mar 25, 2015

@casertap Yes, you can have normal (cookie) based devise for your legacy pages and, as you migrate to angular, use DeviseTokenAuth for your new angular pages. The way I'm handling it now is having the DeviseTokenAuth::Concerns::SetUserByToken check for a warden.user in session before checking the token headers. For old pages -- the user is authenticated via devise. For new angular pages the user is authenticated via DeviseTokenAuth (via ng-token-auth).

@lynndylanhurley
Copy link
Owner

The way I'm handling it now is having the DeviseTokenAuth::Concerns::SetUserByToken check for a warden.user in session before checking the token headers.

@nickL - that sounds like a good strategy. Should we incorporate this behavior into the gem?

@nickL
Copy link
Contributor

nickL commented Mar 25, 2015

@lynndylanhurley: Yeah, I think it may be useful. Here's a quick snippet. Let me know if I'm on the right track and I'll clean it up more and submit a PR:

  def set_user_by_token(mapping=nil)
    # determine target authentication class
    rc = resource_class(mapping)

    # no default user defined
    return unless rc

    # user has already been found and authenticated
    return @resource if @resource and @resource.class == rc

    # parse header for values necessary for authentication
    uid        = request.headers['uid']
    @token     = request.headers['access-token']
    @client_id = request.headers['client']
    @client_id ||= 'default'

    #****  Money line here...  looking for user via warden first..****
    #*********************************************************************
    #
    if warden.user
      user = warden.user
      user.provider ||= "email"
      user.uid ||= user.email
      user.save if user.changed?
      sign_in(:user, user, store: false, bypass: true)
      return @resource = user
   else
      return false unless @token
      # client_id isn't required, set to 'default' if absent

      # mitigate timing attacks by finding by uid instead of auth token
      user = uid && rc.find_by_uid(uid)

@nickL
Copy link
Contributor

nickL commented Mar 25, 2015

Crap, that user.provider= & user.uid stuff is specific to our implementation, worth ignoring.

@lynndylanhurley
Copy link
Owner

@nickL - looks good to me! If you have time to send a PR I'll merge ASAP.

@nickL
Copy link
Contributor

nickL commented Mar 25, 2015

Cool! I'll whip up a PR and add some tests. Thanks dude!

On Wed, Mar 25, 2015 at 12:26 PM -0700, "Lynn Dylan Hurley" [email protected] wrote:

@nickL - looks good to me! If you have time to send a PR I'll merge ASAP.


Reply to this email directly or view it on GitHub.

@casertap
Copy link
Author

@nickL it is an awesome solution thanks a lot.
I can't wait for this feature to be included in the gem.

@spemmons
Copy link

spemmons commented Aug 3, 2015

I'm not sure if this is the best issue to comment on or if I should make a new one.

I am using ActiveAdmin together with this gem and have noticed that /admin/logout (which results in "active_admin/devise/sessions#destroy" and presumably maps to the normal Devise sign-out) sets "current_user" to nil, but /auth/sign_out does not. This is leading to some inconsistencies where I can sign out on using /auth/sign_out, but can directly go to my AA page at /admin and still be signed in...

@Jeehut
Copy link

Jeehut commented Aug 19, 2015

There's now documentation in the Can I use this gem alongside standard Devise? section of the README. Doesn't this solve this issue?

@rossshannon
Copy link

The documentation on this is very difficult to piece together. I’d try to rewrite it but I haven’t gotten my standard Devise actions working again since adding the gem.

From the readme:

Yes! But you will need to enable the support use separate routes for standard Devise. So do something like this:

config/initializers/devise_token_auth.rb

DeviseTokenAuth.setup do |config|
 # enable_standard_devise_support = false
end

Why is the config line commented out? Shouldn’t it be
config.enable_standard_devise_support = true
intead of
# enable_standard_devise_support = false

@alexonozor
Copy link

Can someone help me? What is the solution to this bug? I've been crawling around the internet.

@addicted2sounds
Copy link

I have the issue with the latest version. Original devise seems not to be working after adding this gem

@JohnMerlino2
Copy link

JohnMerlino2 commented Jan 27, 2017

For me, it gives me an error here:

  def set_user_by_token(mapping=nil)
    # determine target authentication class
    rc = resource_class(mapping)

The error message is:

wrong number of arguments (given 1, expected 0)

Apparently, Devise has changed that resource_class no longer accepts an argument? Is that is what is causing this to fail? Because right now, it never gets to the line if DeviseTokenAuth.enable_standard_devise_support

http://stackoverflow.com/questions/41902326/class-context-overrides-module-methods-with-the-same-name

@JohnMerlino2
Copy link

It seems like a lot of people are having the same issue here, dating back to 2015 and we are now in January 2017. I think what happened is that the Devise gem made updates that adversely influenced the behavior of this gem. Since this gem is no longer maintained, this gem can no longer work in conjunction with Devise (for the web). I assume the solution now is to migrate to this gem: https://github.com/gonzalo-bulnes/simple_token_authentication

@ziaulrehman40
Copy link

@JohnMerlino2 Is it true what you said: "Since this gem is no longer maintained, this gem can no longer work in conjunction with Devise (for the web)"?

Because this repo seems active and last commit was a month ago.

@tit1
Copy link

tit1 commented Mar 6, 2017

I was having the same issue where i need to sign a user into both devise and devise-token-auth. First i set up my login page to be a standard Devise login page. I than extended Devise::SessionController#create:

def create
  super do |user|
    session[:token] = true
  end
end

In the ApplicationController I added:

before_filter :set_token

def set_token
  if session[:token] && user_signed_in?
    newAuth = current_user.create_new_auth_token
    response.headers.merge!(newAuth)
    @auth_token = newAuth
    session.delete(:token)
  else
    @auth_token = false
  end
end

Finally in views/layouts/application.html.haml i added:

- if @auth_token
  :coffee
    myApp.controller 'cookieController', ($scope, $resource, $http, $mdDialog, $auth, ipCookie ) ->
      ipCookie('auth_headers', "{\"access-token\": \"#{@auth_token['access-token']}\",\"token-type\": \"Bearer\",\"client\": \"#{@auth_token['client']}\",\"expiry\": \"#{@auth_token['expiry']}\",\"uid\": \"#{@auth_token['uid']}\"}", {path: "/",expires: 9999,expirationUnit: 'days',secure: false})
      ipCookie('currentConfigName', 'default', {path: "/",expires: 9999,expirationUnit: 'days',secure: false})
  %div{'ng-controller'=>'cookieController'}

I realize that this is a little hacky and that my code could be a lot cleaner; that said i wanted to share it with you as a possible solution for people looking to authenticate with both devise and devise-toke-auth.

@jotolo
Copy link
Contributor

jotolo commented May 9, 2017

I was working in a similar case where I needed to use both, devise+devise_token_auth in a spree application. I was trying to implement authentication for spree_api and migrating the authentication of spree system(Full Stack App) to devise.
I found a way to do it and it's very simple.It's not a common thing in rails but it works great. The idea is to have a main application_controller.rb in your application and particular application_controllers for each section. In my case one for admin system in spree and the other one for API.

#controllers/api/v1/application_controller.rb
module Api
  module V1
    class ApplicationController < ApplicationController
      skip_before_action :verify_authenticity_token
      include DeviseTokenAuth::Concerns::SetUserByToken
    end
  end
end

In the API controller I included the regular DeviseTokenAuth concern to manage auth in the app that controls this application_controller.rb. Note that this controller inherits from the main application_controller.

#controllers/admin/application_controller.rb
  module Admin
    class ApplicationController < ApplicationController
      before_action :authenticate_user!
    end
  end

This controller is, well, natural behavior of devise. I just needed to add the before action method.
We just need the base application_controller ;)

class ApplicationController < ActionController::Base
  protect_from_forgery with: :exception, if: :verify_api

  def verify_api
    params[:controller].split('/')[0] != 'devise_token_auth'
  end
end

Our main application_controller.rb looks like this. You need to keep the CSRF token protection but you can avoid it when an API request arrive.
The idea is to redirect each flow in your application. the ones that belongs to your full-stack app and the other ones that belongs to your API. Well, in this case to my API 😄
This scenario was tested using devise (4.2.0) and devise_token_auth (0.1.40).
I hope I can help someone with this example.
Regards

@mrkrlli
Copy link
Contributor

mrkrlli commented May 30, 2018

I've created a PR to add @jotolo suggestion to the FAQ: #1175

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests