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