Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Devise/OmniAuth Override default callback url

I'm using Devise 3.5 with Omniauth in a Rails 4 app. I've created an integration with Facebook that allows a user to connect their Facebook account to my app. Currently when the user clicks the connect button, they're sent to /user/auth/facebook and then redirected to the callback url that Omniauth generates: /user/auth/facebook/callback. What I'd like to do is manually override this callback url in some cases - meaning that I don't want to override it in an initializer - with a fully qualified url. For example, if a user starts out on http://www.example.com/ I might want to override the default callback url with http://app.example.com/user/auth/facebook/callback.

My app has dynamic subdomains and a user will (almost) always begin the authentication process on a subdomain. Unfortunately it seems that Facebook doesn't support wildcards in oauth redirect urls, which is why I want the ability to detect if a user is on a subdomain and adjust the callback url to something that I have whitelisted on my Facebook app so that the authorization process succeeds.

From what I've read, the url helper omniauth_authorize_path accepts additional arguments to be passed on as parameters. I've tried passing a custom callback path in like so, but without success:

user_omniauth_authorize_path(:facebook, callback_path: @custom_callback)

I've also tried changing callback_path to redirect_url and redirect_uri, but nothing seems to work. When I look at the link that's generated, it does indeed include the callback as a parameter in the url, but when I click the link, I'm redirected back to the default callback url instead of the custom callback url.

like image 933
Daniel Bonnell Avatar asked Mar 10 '16 15:03

Daniel Bonnell


2 Answers

Here's how I solved this problem. I'm sure there are other ways, but this seems like the simplest most elegant solution I could come up with.

In config/routes.rb I set up an auth subdomain. All my Oauth connect requests will start on different subdomains and then Facebook is set up to forward those users back to the auth.example.com subdomain.

constraints AuthRedirect do
    devise_scope :contact do
        get '/auth/facebook/callback' => 'omniauth_callbacks#facebook'
        post '/auth/facebook/callback' => 'omniauth_callbacks#facebook'
    end
end

Here is /lib/auth_redirect.rb. This just checks if the subdomain is auth and captures that traffic. This is placed at the top of my routes list so as to take precedence over other subdomains.

class AuthRedirect
    def self.matches?(request)
        request.subdomain.present? && request.subdomain == 'auth'
    end
end

Then in my client, when a user clicks the Connect with Facebook button, I send them to /auth/facebook?contact_id=<id>. From here Devise directs them to Facebook, which then redirects them back to https://auth.example.com/.

Then in OmniauthCallbacksController#facebook I can pull the user's id from the omniauth params like so:

auth = env["omniauth.auth"]
contact = Contact.find(env['omniauth.params']['contact_id'])

From here I can persist the credentials to the database and the redirect the user back to the appropriate subdomain. This solution avoids problems with CSRF tokens and more importantly does not require me to use Ruby/ERB to build the omniauth authorize path that the user is sent to when they click the connect button.

like image 177
Daniel Bonnell Avatar answered Nov 15 '22 09:11

Daniel Bonnell


have you tried with redirect_uri ?

user_omniauth_authorize_path(:facebook, redirect_uri: @custom_callback)

EDIT: sorry I missed the second part of your post.

I actually have the same problem in production but it works perfectly on a staging environment. The only difference is about the callback url on staging which has one more subdomain *.staging.domain.com

By the way you can provide a static callback_url in the devise initializer file:

config.oaumniauth :facebook, ..., callback_url: 'url right here'

I'm on this issue this yesterday. Either I provide a static callback url but facebook raises me an CRSF error:

omniauth: (facebook) Authentication failure! csrf_detected: OmniAuth::Strategies::OAuth2::CallbackError, csrf_detected | CSRF detected

Or I let devise set the callback_url dynamically which gonna look like

https://*.domain.com/DEVISE_MODELS/auth/facebook

and in this case I get a straight non matching/whitelisted callback url during FG loggin in process.

EDIT2:

GOOD! I made it. I'm able to get oauth login in with wildcard subdomain.

  1. Provide a static callback_url in your devise initializer
  2. add the domain to your session store as : domain: ".domain.com"

With that I'm getting neither CRSF error nor nunmatching CB url/whitelisted.

Hope it'll work for you !

like image 34
axzwl Avatar answered Nov 15 '22 08:11

axzwl