I am trying to implement omniauth-twitter
with Devise in Ruby-on-Rails with no success.
According to the definitive article of Devise, the link
<%= link_to "Sign up with twitter", user_twitter_omniauth_authorize_path,
method: :post %>
should take the visitor to Twitter (Note I have disabled turbo
site-wide with Turbo.session.drive = false
and so turbo
is irrelevant).
However, it just displays
Not found. Authentication passthru.
I notice the route looks wrong in the first place:
% bin/rails routes -g omni
Prefix Verb URI Pattern Controller#Action
user_twitter_omniauth_authorize GET|POST /users/auth/twitter(.:format) users/omniauth_callbacks#passthru
user_twitter_omniauth_callback GET|POST /users/auth/twitter/callback(.:format) users/omniauth_callbacks#twitter
It apparently points to Users::OmniauthCallbacksController#passthru
, which is a non-existent method, hence the error?
This problem has been reported multiple times in Stackoverflow and Github (e.g., Github, SO1, SO2). A general advice seems to be using POST as opposed to GET. However, besides it is definitely POST in my case (as confirmed with a log file), I doubt if it is relevant to the routes!
What is the probable cause of this probblem and how can I solve it?
I confirm I am using OA1 API keys as opposed to Twitter OA2 (the latter is not supported by Omniauth, yet).. Also, as the doc of omniauth-twitter suggests, I confirm that "User authentication set up" is active in the Twitter Dev center to allow users to log in.
My relevant files are as follows:
# Gemfile
gem 'devise'
gem 'devise-i18n'
gem 'omniauth', '~> 2.1' #, '1.9.1'
gem 'omniauth-twitter'
gem 'omniauth-rails_csrf_protection'
# /config/initializers/devise.rb
Devise.setup do |config|
config.omniauth :twitter, 'MY_APP', 'MY_SECRET'
OmniAuth.config.logger = Rails.logger if Rails.env.development? # for debug
end
Note there are no Omniauth or Twitter-related configs in config/initializers/
. Just devise.rb
.
# /models/user.rb
class User < ApplicationRecord
devise :database_authenticatable, :registerable, #...snipped...
:omniauthable, omniauth_providers: %i(twitter)
def self.from_omniauth(auth)
find_or_create_by(provider: auth.provider, uid: auth.uid) do |user|
user.display_name = auth.info.nickname.strip
user.skip_confirmation!
end
end
end
# /app/controllers/users/omniauth_callbacks_controller.rb
class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
skip_before_action :verify_authenticity_token, only: [:twitter]
def twitter
callback_from __method__
end
def callback_from(provider)
# See User model
@user = User.from_omniauth(request.env['omniauth.auth'])
if @user.persisted?
sign_in_and_redirect @user, event: :authentication
set_flash_message(:notice, :success, kind: provider.to_s.capitalize) if is_navigational_format?
else
session["devise.#{provider.to_s}_data"] = request.env['omniauth.auth'].except(:extra)
redirect_to new_user_registration_url(from_omniauth_callback: true)
end
end
def failure
redirect_to root_path
end
end
# /config/routes.rb
Rails.application.routes.draw do
devise_for :users, except: [:destroy],
controllers: { omniauth_callbacks: 'users/omniauth_callbacks' }
end
View (the turbo-part is meaningless, for it is globally turned off).
<%# /app/views/devise/registrations/new.html.erb >
<%= link_to t(".sign_up_with_twitter"), user_twitter_omniauth_authorize_path,
method: :post, data: { turbo: false } %>
The standard output of the server (bin/dev
in Rail 7):
00:... | I, [2022-...6 #793] INFO -- : Started POST "/en/users/auth/twitter" for 127.0.0.1 at 2022-11-27 00:33:14 +0000
00:... | I, [2022-...4 #793] INFO -- : Processing by Users::OmniauthCallbacksController#passthru as HTML
00:... | I, [2022-...0 #793] INFO -- : Parameters: {"authenticity_token"=>"[FILTERED]", "locale"=>"en"}
00:... | D, [2022-...0 #793] DEBUG -- : Rendering text template
00:... | I, [2022-...7 #793] INFO -- : Rendered text template (Duration: 0.0ms | Allocations: 10)
00:... | I, [2022-...9 #793] INFO -- : Completed 404 Not Found in 4ms (Views: 2.5ms | ActiveRecord: 0.0ms | Allocations: 1170)
Version information
omniauth-rails_csrf_protection
(0.1.2) → (1.0.1)Gemfile
did not specify the version and yet a lower-version was installed. I nowbundle install
with'~> 1.0'
. The same error still remains (after server-restart).
omniauth
(2.1.0)omniauth-oauth
(1.2.0)omniauth-twitter
(1.4.0)devise
(4.8.1)rails
(7.0.4)ruby
(3.1.2)
That's it. Thank you.