OmniAuth with Multiple Models - some more details?

800 views
Skip to first unread message

Brenner Spear

unread,
Sep 9, 2015, 3:23:41 PM9/9/15
to Devise
I am building an app that has multiple models that can be logged in with different services.

I have a Shoppers model that can be logged in with Instagram

I have a Brands model that can be logged in with Big commerce, and will be able to authenticate their Instagram.

The Instructions for using OmniAuth with multiple models is somewhat incomplete:

Step 1 is: Remove the :omniauthable argument from your models.


It doesn't mention I also have to remove the line
 omniauth_providers: [:instagram]

then I get the error:

ArgumentError: Mapping omniauth_callbacks on a resource that is not omniauthable



So I guess that I have to go remove something from my routes.rb file. I go change:
devise_for :shoppers, controllers: {omniauth_callbacks: "shoppers/omniauth_callbacks"}
to:
devise_for :shoppers

which let's rake routes work fine. Now these two routes no longer exist:
shopper_omniauth_authorize GET|POST /shoppers/auth/:provider(.:format)        shoppers/omniauth_callbacks#passthru {:provider=>/instagram/}
shopper_omniauth_callback GET
|POST /shoppers/auth/:action/callback(.:format) shoppers/omniauth_callbacks#(?-mix:instagram)


The instructions demonstrate a way to recreate the latter of the two, to some extent. I add this to my routes.rb file:

get "/auth/:action/callback", to: "shoppers/omniauth_callbacks", constraints: {action: /instagram/}

which gives me the route:

                          GET    /auth/:action/callback(.:format) shoppers/omniauth_callbacks#(?-mix:instagram)

But the former of those two routes doesn't exist, so now I get the error:

No route matches [GET] "/shoppers/auth/instagram"


When I click on 'Authorize with Instagram'.


How do I get all of this to work?


Thanks



Guilherme Simões

unread,
Sep 9, 2015, 6:32:07 PM9/9/15
to Devise
The first route which you talk about is this:

shopper_omniauth_authorize GET|POST /shoppers/auth/:provider(.:format)  shoppers/omniauth_callbacks#passthru {:provider=>/instagram/}

You do not need this route. That's not the reason an error is occurring.


You only need the second route, which you setup correctly. However, you did not setup correctly the callback on your Instagram app.
On your Instagram app you defined the callback as /shoppers/auth/instagram but on your Rails app you defined your route as  /auth/:action/callback, which is the same as /auth/instagram/callback.
These two URLs have to match. Usually, these OAuth apps require full URLs, so try setting your callback on Instagram as http://localhost:3000/auth/instagram/callback.

Brenner Spear

unread,
Sep 9, 2015, 6:47:46 PM9/9/15
to Devise
I later updated my route to 
 match "shoppers/auth/:action/callback" => "shoppers/omniauth_callbacks", constraints: {action: /instagram/}, via: [:get, :post]

The link that I click to 'Authorize your Instagram' is: 'http://localhost:3000/shoppers/auth/instagram'. It has always been this when I was using:
devise_for :shoppers, controllers: {omniauth_callbacks: "shoppers/omniauth_callbacks"}

And the first route is what routed that link to a valid controller#action. Now, that link doesn't have anywhere to go. Where am I supposed to map that link?

Guilherme Simões

unread,
Sep 9, 2015, 7:10:07 PM9/9/15
to Devise
Devise creates that first route so that it can internally deal with OmniAuth. Notice that that route is redirected to a passthru action.
Since you are using OmniAuth in a way that is not integrated with Devise, you do not need that route.

OmniAuth will redirect all routes that begin with  /auth to the correct OAuth URLs. So you don't actually have to define those routes.
What you have to do is define the callback routes, which are the URLs that the OAuth providers use to communicate back to you.

You now have all that correctly setup. The only thing missing is changing the link that you click to 'Authorize your Instagram'.
Change the link in the view to /auth/instagram instead of  /shoppers/auth/instagram.

Brenner Spear

unread,
Sep 9, 2015, 7:25:00 PM9/9/15
to Devise
Okay, thanks. Does this mean I can't use my shoppeers/omniauthCallbacksController.rb anymore?

and I have to create a different callback controller not in a folder to call the Instagram action that will run Shopper.from_omniauth(auth)?

Brenner Spear

unread,
Sep 9, 2015, 7:30:25 PM9/9/15
to Devise
Ah.. I forgot to change my route to: 
match "/auth/:action/callback" => "shoppers/omniauth_callbacks", constraints: {action: /instagram/}, via: [:get, :post]
(removing the /shopper/ from the first string)

but now I'm getting the error:
Could not find devise mapping for path "/auth/instagram/callback?code=

and the ways to fix it are not anything like in the devise wiki page instructions - they're telling me to wrap my route in:
devise_scope :user do get "/some/route" => "some_devise_controller" end


Should I be doing that?

Guilherme Simões

unread,
Sep 9, 2015, 8:37:42 PM9/9/15
to Devise
You can still use your shoppees/omniauthCallbacksController.rb. Your URLS do not have to match exactly your folder structure.
If you still want to change your OmniAuth routes, try this: http://stackoverflow.com/questions/10033413/how-to-change-route-of-omniauth-from-auth-provider-to-myapp-auth-provider

As for what in Devise's wiki, just ignore it. To support multiple models you have to use OmniAuth in a way that is decoupled from Devise.

I'd say that that new error is due to your OmniAuth configuration still being tied to Devise.
Make sure that the configuration is not inside the file devise.rb, but inside another initializer, which you can name omniauth.rb.
Google it :)

Brenner Spear

unread,
Sep 9, 2015, 8:51:27 PM9/9/15
to Devise
I had already removed the config from devise.rb and put it in omniauth.rb.

My Shopper/Omniauth_Callbacks_Controller is from a devise class:

class Shoppers::OmniauthCallbacksController < Devise::OmniauthCallbacksController

does this have anything to do with it?

Is there an example of an application that uses omniauth & devise with two different models that I could take a look at to see what's different?

Guilherme Simões

unread,
Sep 9, 2015, 9:06:02 PM9/9/15
to Devise
Yeah, that's probably it. Make your controller inherit from ApplicationController instead of Devise::OmniauthCallbacksController.

It does not include Devise but that shouldn't be a problem because, again, you want to decouple OmniAuth from Devise.
It also does not include multiple models, but that's just Rails and Ruby.

Anyway, I haven't used Rails or OmniAuth in a while, so maybe someone else can help you :)
Reply all
Reply to author
Forward
0 new messages