Pregunta

I want to implement login and register with Twitter omniauth on my site. I have followd this Railscast, but when I click the "Log in with twitter" link, I receive a 401 Unauthorized. When I look in the log I see this:

GET "/users/auth/twitter/callback?oauth_token=xxx&oauth_verifier=xxx
omniauth: (twitter) Callback phase initiated.
Processing by OmniauthCallbacksController#twitter as HTML
  Parameters: {"oauth_token"=>"xxx", "oauth_verifier"=>"xxx"}
  User Load (1.3ms)  SELECT "users".* FROM "users" WHERE "users"."provider" = 'twitter' AND "users"."uid" = '9999' ORDER BY "users"."id" ASC LIMIT 1
   (0.3ms)  BEGIN
   (0.2ms)  COMMIT
Completed 401 Unauthorized in 13ms

When I look in the omniauth controller, it has found a user, but it seems to fail on the sign_in_and_redirect user line.

class OmniauthCallbacksController < Devise::OmniauthCallbacksController
  def all
    user = User.from_omniauth(request.env["omniauth.auth"])
    if user.persisted?
      # it reaches this
      flash.notice = I18n.t('.devise.omniauth_callbacks.success')
      sign_in_and_redirect user
    else
      session["devise.user_attributes"] = user.attributes
      redirect_to new_user_registration_url, notice: I18n.t('.devise.omniauth_callbacks.failure')
    end
  end
  alias_method :twitter, :all
end

In config/devise.rb I have added the key and secret like this:

config.omniauth :twitter, ENV.fetch("TWITTER_CONSUMER_KEY"), ENV.fetch("TWITTER_CONSUMER_SECRET")

And then the actual values are stored in .rvmrc like this:

export TWITTER_CONSUMER_KEY=xxx
export TWITTER_CONSUMER_SECRET=xxx

This probably means that it tries to login the found user but fails on some validation right? But I removed all validations in the user model to check what happens, and I still get this error. Anyone any idea what might be wrong here?

¿Fue útil?

Solución 2

The issue should be strong parameters. I would suggest you get all you want from request.env["omniauth.auth"] into some variables instead of directly using in for creation or find.

def self.from_omniauth(auth)
 uid = auth[:uid]
 provider = auth[:provider]

 User.where(provider: provider, uid: uid).first
end

This should fix the unauthorized error.

Otros consejos

I had the same issue ("Omniauth returns a 401 unauthorized") but the cause was different.

In my User#from_omniauth I do this

where(provider: auth.provider, uid: auth.uid).first_or_create

which means that it creates a new user if one was not already there. Also, my User is devise :confirmable, and unconfirmed User can not sign in. That is why the authentication failed.

There would have been an error message stating this, but in the view that I was redirected to there was no:

<p class="notice"><%= notice %></p>
<p class="alert"><%= alert %></p>

So, the solution was to add this to the method in the CallbacksController:

def github
  @user = User.from_omniauth(request.env['omniauth.auth'])

  if @user.persisted?
    @user.skip_confirmation!
    @user.save
  #...

skip_confirmation is a devise method and it does this on the User:

self.confirmed_at = Time.now.utc

so, alternatively this could have been done in User.from_omniauth

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top