Is it possible to scope omniauth paths to a resource? For example, let's say we have an arbitrary website building website, where I can scope the website in routes via something like:
get ":site_name", :to => "sites#show"
I now want to add authentication via omniauth, but have it work on each individual site, so if I could specify the omniauth routes manually, it might be:
get ":site_name/auth/:provider", :to => "omniauth#whatever"
get ":site_name/auth/failure", :to => "omniauth#failure"
get ":site_name/auth/:provider/callback", :to => "my_omniauth_callbacks#auth"
We have tried using the path_prefix like so:
Rails.application.config.middleware.use OmniAuth::Builder do
configure do |config|
config.path_prefix = "/:site_name/auth"
end
# Providers
end
but it just means we have to visit /:site_name/auth/provider
instead of being able to use /my_site_1/auth/provider
We were able to accomplish this with the following omniauth initializer (including configuration for google openid provider, though the same concept would probably apply to other providers):
require "openid/store/filesystem"
Rails.application.config.middleware.use OmniAuth::Builder do
AUTH_REGEX = /^\/([^\/]+)\/auth\/([^\/]+)$/
CALLBACK_REGEX = /^\/([^\/]+)\/auth\/([^\/]+)\/callback$/
SITE_REGEX = /^\/([^\/]+)(?:\/auth\/([^\/]+)\/callback)?/
configure do |config|
config.on_failure = lambda do |env|
match_data = SITE_REGEX.match env["PATH_INFO"]
if match_data
provider = match_data[2] || "unknown"
location = "/#{match_data[1]}/auth/#{provider}/failure"
else
location = "/unknown/auth/unknown/failure"
end
Rack::Response.new(["302 Moved"], 302, "Location" => location).finish
end
end
callback_path = lambda do |env|
env["PATH_INFO"] =~ CALLBACK_REGEX
end
request_path = lambda do |env|
match_data = AUTH_REGEX.match env["PATH_INFO"]
if match_data
"/#{match_data[1]}/auth/#{match_data[2]}/callback"
end
end
provider :openid, :name => "google",
:identifier => "https://www.google.com/accounts/o8/id",
:store => OpenID::Store::Filesystem.new("/tmp"),
:callback_path => callback_path,
:request_path => request_path
end
This will utilize the site name in the callback, the original auth link, as well as the failure link. It can then be paired with the following routes in routes.rb:
get "/:site_name/auth/:provider/failure", :to => "my_omniauth#failure"
post "/:site_name/auth/:provider/callback", :to => "my_omniauth#callback"