In my project, I have two type of users: job seekers and hiring managers. Job seekers don't have a model, they are just able to apply for jobs using the data received from from third-party providers while authenticating thru Omniauth. Hiring managers' info is stored in devise User model. Hiring managers also must be able to sign in with their company's Google email account. So, first I built job seekers' authentication using Omniauth 1.0.0, Rails 3.1.3:
omniauth.rb
require 'omniauth-openid'
require 'openid/store/filesystem'
Rails.application.config.middleware.use OmniAuth::Builder do
provider :openid, :store => OpenID::Store::Filesystem.new('./tmp'), :name => 'google', :identifier => 'https://www.google.com/accounts/o8/id'
provider :facebook, "xxxxxxxxx", "xxxxxxxxxxxxxxxxxxxxxxxxxxxx",
{:scope => 'email, offline_access, publish_stream', :client_options => {:ssl => {:ca_file => '/usr/lib/ssl/certs/ca-certificates.crt'}}}
provider :twitter, "xxxxxxxxxxx", "xxxxxxxxxxxxxxxxxxxxxxxxxxx"
provider :linkedin, "xxxxxxxxxxx", "xxxxxxxxxxxxxxxxxxx"
end
in routes.rb
:
match '/auth/:provider/callback', :to => 'sessions#authenticate_jobseeker'
match '/auth/failure', :to => 'sessions#failure'
in sessions_controller.rb
def authenticate_jobseeker
session[:jobseeker] = request.env['omniauth.auth']
if valid_job_seeker?
redirect_to new_job_application_path(...)
else
redirect_to request.env['omniauth.origin'] || root_path, alert: "Authentication failure"
end
end
Up to this point everything worked fine. However, when I started implementing Google sign on for User model, and added :omniauthable to it, my job seeker authentication broke. I am using Devise 1.5.2:
user.rb
class User < ActiveRecord::Base
#...
devise :database_authenticatable, :registerable,
... :lockable, :omniauthable
#...
end
in devise.rb
:
config.omniauth :open_id, :store => OpenID::Store::Filesystem.new('./tmp'), :name => 'google', :identifier => 'https://www.google.com/accounts/o8/id', :require => 'omniauth-openid'
in routes.rb
:
devise_for :users, :controllers => { :omniauth_callbacks => "users/omniauth_callbacks" } do
get '/users/auth/:provider' => 'users/omniauth_callbacks#passthru'
end
At this point, Users' authentication worked, but job seekers' did not. After searching for a while, the issue was fixed by adding :path_prefix => "/auth"
to every provider in omniauth.rb
.
The only problem now, is when job seeker does not allow access to its data (i.e. presses "Don't Allow" and comes back to the application), I get following RuntimeError for every provider:
Could not find a valid mapping for path "/auth/twitter/callback"
Parameters:
{"denied"=>"mKjVfMRwRAN12ZxQ9cxCoD4rYSLJIRLnEqgiI"}
top of the trace:
devise (1.5.2) lib/devise/mapping.rb:48:in `find_by_path!'
devise (1.5.2) lib/devise/omniauth.rb:17:in `block in <top (required)>'
omniauth (1.0.0) lib/omniauth/strategy.rb:418:in `call'
omniauth (1.0.0) lib/omniauth/strategy.rb:418:in `fail!'
omniauth-oauth (1.0.0) lib/omniauth/strategies/oauth.rb:63:in `rescue in callback_phase'
omniauth-oauth (1.0.0) lib/omniauth/strategies/oauth.rb:45:in `callback_phase'
omniauth (1.0.0) lib/omniauth/strategy.rb:200:in `callback_call'
omniauth (1.0.0) lib/omniauth/strategy.rb:166:in `call!'
omniauth (1.0.0) lib/omniauth/strategy.rb:148:in `call'
omniauth (1.0.0) lib/omniauth/strategy.rb:168:in `call!'
omniauth (1.0.0) lib/omniauth/strategy.rb:148:in `call'
omniauth (1.0.0) lib/omniauth/strategy.rb:168:in `call!'
omniauth (1.0.0) lib/omniauth/strategy.rb:148:in `call'
omniauth (1.0.0) lib/omniauth/builder.rb:30:in `call'
I've been trying to solve it for a while now. Any help is greatly appreciated. Let me know, if I can provide additional info.
Are you using omniauth["user_info"] in your models somewhere? In my case, I was accessing
and that would crash and I would get the same error, being caught by devise.
In my app as well, we use omniauth directly (for businesses) as well as use device+facebook for user logins.
Havent yet figured out to not get failure caught by devise though. Devise registers it's own failure app. Will update when i figure it out.
Update: I'm sorry it seems I misread part of your question. You can see a clear failure to authorize from the remote webapp which seems to stuff up and not a masked exception from the code (as was in my case).
Answering my own question. So, final decision was to go with pure Omniauth implementation. I removed
:omniauthable
fromUser
model, removedconfig.omniauth...
fromdevise.rb
, removed:omniauth_callbacks
devise routes fromroutes.rb
. So, all users (no matter what role) would use ame callback routes and hitsessions_controller#authenticate_jobseeker
action (should consider renaming the action?):and
User.find_from_oauth
:This implementation satisfied all of the requirements.