2

I have omniauth-facebook to sign up/sign in. After signin, I want to redirect the user to the page where they hit the auth block. I'm using sign_in_and_redirect but it seems to be calling the last url, which in this case is

http://localhost:3000/auth/facebook?callback_url=localhost%2Fauth%2Ffacebook%2Fcallback

So it keeps doing: Redirected to http://localhost:3000/auth/facebook?callback_url=localhost%2Fauth%2Ffacebook%2Fcallback

And it keeps calling this callback in a loop until it crashes. Here is the omniauth controller:

   def facebook
     generic_callback( 'facebook' )
   end

   def generic_callback( provider )
    @identity = Identity.find_for_oauth env["omniauth.auth"]
    if @identity.user != nil
      @user = @identity.user || current_user
    else
      @user = User.from_omniauth(request.env["omniauth.auth"])
    end

    if @user.nil?
      @user = User.create( email: @identity.email || "" )
      @identity.update_attribute( :user_id, @user.id )
    end

    if @user.email.blank? && @identity.email
      @user.update_attribute( :email, @identity.email)
    end

    if @user.persisted?
      @identity.update_attribute( :user_id, @user.id )
      @user = User.find(@user.id)
      sign_in_and_redirect @user, event: :authentication
      return
    else
      session["devise.#{provider}_data"] = env["omniauth.auth"]
      redirect_to new_user_registration_url
      return
    end
  end

The devise helper:

  def sign_in_and_redirect(resource_or_scope, *args)
    options  = args.extract_options!
    scope    = Devise::Mapping.find_scope!(resource_or_scope)
    resource = args.last || resource_or_scope
    sign_in(scope, resource, options)
    redirect_to after_sign_in_path_for(resource)
  end

Routes

  resources :users
  devise_for :users, controllers: { registrations: "users/registrations", sessions: "users/sessions",  :omniauth_callbacks => "users/omniauth_callbacks" }, path: '', path_names: { sign_in: 'sign_in', sign_out: 'logout', sign_up: 'sign_up'}
  match '/auth/:provider/callback', to: 'sessions#create', via: [:get, :post]

How can I make it sign in regularly?

gwalshington
  • 1,418
  • 2
  • 30
  • 60
  • Could you please provide more context? Any Devise-related code omitted from the question? Maybe you have overwritten `after_sign_in_path_for` somewhere in the `ApplicationController` or something else? I'm asking because I have structurally the same code as described in the question and it works as intended out of the box. – jibiel Jun 06 '20 at 14:24
  • Thanks! It's clear now. See my updated answer. – jibiel Jun 06 '20 at 15:01

1 Answers1

1

Ok, here's the problem. This line creates the recursion:

match '/auth/:provider/callback', to: 'sessions#create', via: [:get, :post]

Change it to:

get 'auth/facebook/callback', to: 'users/omniauth_callbacks#facebook'

If you'll refactor #generic_callback method a bit to use params[:provider] instead of the provider argument, you'll then be able to get rid of hard-coding of the omniauth providers in your routes:

get 'auth/:provider/callback', to: 'users/omniauth_callbacks#generic_callback'

To clarify the problem:

In the implementation described in the question users/omniauth_callbacks#generic_callback is not called at all. Instead you're trying to call sessions#create which is used to sign in users with the app credentials (usually, email and password), whereas in the omniauth case user should be created and authenticated in a specific way (via generic_callback and sign_in_and_redirect in your case).

Simply put:

You don't have to call sessions#create to create user session here, #generic_callback with #sign_in_and_redirect does just that.

jibiel
  • 8,175
  • 7
  • 51
  • 74
  • How do I get 2 paths ago. The issue is that the user clicks 'sign in' and it redirects to FB, and then FB sends user back to the page with an auth token. So in the omniauth controller, the request.fullpath is `http://localhost:3000/auth/facebook/callback?code=` - if the user needs to sign in to continue, they need to be redirected to the page they are on, if they are just signing in, they need to be redirected to the dashboard_path – gwalshington Jun 06 '20 at 14:09
  • You can check the stored path in your callback method like this `stored_location_for(:user)`. Devise won't store just any last URL including Omniauth-related ones. It only stores locations when request was failed due to authentication errors and the like. – jibiel Jun 06 '20 at 14:53
  • Thanks to your help, I changed some routes, and saw I was also calling after_sign_in in my application controller, which was causing some issues. It's still not redirecting correctly after omniauth login, but it's not re-calling the callback url either, which is what this ? was about. Thanks! – gwalshington Jun 07 '20 at 13:46