How to do omniauth on wildcard subdomain - ruby-on-rails

I'm have omniauth working in my Rails app on the top level domain.
Now I want to do it on any given subdomain (users each get their own subdomain assigned dynamically).
I can't find a way to dynamically change the callback url on the fly with omniauth
Leaving it as is, in the callback I can see the referrer and know which subdomain they came from, and log them in, but when I then redirect them to their subdomain they are logged out because the session was on the top level domain.
I'm using the omniauth-facebook gem if that matters: https://github.com/mkdynamic/omniauth-facebook
What's the best way to handle this?

I don't think that Omniauth let's you change this dynamically, but you can share the session between all subdomains, and continue to use the redirection approach. Just change your session_store to include domain (and tld_length if you need it - more details here)
Rails.application.config.session_store ... , domain: :all

Related

Rails: Multi-tenancy with Devise and Apartment gem

I'm creating a multi-tenant app using devise and apartment gems. I'm using postgresql database. I've created a few models. 'User' model is in global namespace and it is used for authentication by devise gem. There are some other models (e.g. Project, Setting etc) which are in tenant namespace.
I've followed this tutorial for creating this multi-tenance app: https://gorails.com/episodes/multitenancy-with-apartment?autoplay=1
The multi-tenancy feature is working fine in a sense that if I login to two separate subdomains (e.g. user1.example.com and user2.example.com) from their relevant accounts (e.g. user1#gmail.com and user2#gmail.com) it works fine and I can create unique records for each tenant.
Now, the issue is, I can login to any subdomain using any email and the tenant records would be shown based on the subdomain present in address bar. e.g. I can login with user1#gmail.com at user2.example.com and it will succesfully autheticate and will display records of user2 tenant.
My question is, while logging in how can I check if current user's subdomain matches with the requested subdomain (on address bar), if it matches proceed with authentication and display admin dashboard and if not (logging in from wrong subdomain or from TLD) authenticate the user but redirect him to his relevant subdomain's dashboard. How can I do that?
UPDATE # 1:
I was able to restrict the user login to their specific sub-domain by using minor devise configuration. In devise.rb file I've added :subdomain attribute in the list of authentication keys, so it will also check for correct subdomain value together with email, however I'm not sure how to provide the subdomain value to the login form correctly. I can use a hidden field like this in login form <%= f.hidden_field :subdomain, value: request.subdomain %> but it is hackable as user can change it's value from browser inspector.
UPDATE # 2:
I was able apply a fool proof method to restrict user login to their specific sub-domain. I've followed this method: https://github.com/plataformatec/devise/wiki/How-to:-Scope-login-to-subdomain
Now, my only issue is that user is unable to login from TLD (e.g. example.com), I want it to be possible but after login user must be redirected to their relevant sub-domain with alive session.
Supposing you're saving the subdomain on the User model, you can create a validation in your controller you can use something like:
if user.subdomain == request.subdomain
redirect_to root_url(subdomain: user.subdomain)
else
everything_is_ok
end
If you store your subdomain in your User table and if you check it via request.subdomain then how can someone join the another tenant(company) ? They can be included in more than one company.
That's why, I created 2 middle tables to handle it.
I've user table for all of my users.
I've account table to store subdomains with its creator.
And I've account_permissions to find out who are authorized to where.
So, when user1 comes to user2.example.com, I'm querying to my Account_permissions and if it has permission for user2.example.com, I let it go.
This way seems like sense.
If someone still have a similar problem and is not very expert in ROR, I suggest building the base app first and then making it multi_tenant using that video.
After building your app, you only need to install the apartment gem, then make a model which stores tenants information and then exclude it from being multi_tenanted.

Customize Devise Cookie

I'm using devise in my rails application. I have it configured in a tenanted manor in which accounts/sessions are scoped to a subdomain. For example:
http://subdomain1.example.com/
http://subdomain2.example.com/
...
This works well but I want to have an additional subdomain for "super-admins" that allows those users navigate to all the other subdomains without the need to reauthenticate. This would be something like:
http://admin.example.com/
Is it possible to customize the cookie that gets generated on only the admin subdomain so that it is valid on all other subdomains?
Cookie domains are more inclusive the less specifically they are defined, so if you have a controller that only serves the admin subdomain, you should be able to set a cookie for the .example.com (or example.com) domain and expect it to be available to all other subdomains.
These docs describe the process for selectively setting the cookie domain.

Authenticating Custom url with Devise without having actual controller/action (Rails)

I am using Devise gem in my application and it work fine.
I use omniauth to authenticate Twitter users, and when user types in http://www.mydomain.com/addtwitter user will be redirected to Twitter authentication page.
In devise gem, by default when user loads the page /auth/twitter it takes user to authorization page. So to customize this i added below code in my routes.rb file.
match "/addtwitter" => redirect("/auth/twitter")
But i would like to make the /addtwitter functionality only to the logged in user.
How do i achieve this without actually creating a controller/action in rails?
is this even possible?
In devise, you can specify routes that only apply to logged in users.
authenticated :user do
match "/addtwitter" => redirect("/auth/twitter")
end

OmniAuth dynamic client options site within the strategy

I have a rails app set up as an OAuth2 provider (using Doorkeeper). The app uses a different subdomain per user account (or an entirely different domain through a cname record)
i.e.
user1.myrailsapp.com
user2.myrailsapp.com
www.mycustomdomain.com
On the provider side, everything is working as expected.
I also have a second app that is a client making use of the first app's exposed API. I have a version of the client working but only with a hard coded site url in the OmniAuth strategy.
The question is, how can I dynamically set the strategy url on a per request basis.
For anyone interested, the solution is in the use of dynamic providers: https://github.com/intridea/omniauth/wiki/Dynamic-Providers
Rails.application.config.middleware.use OmniAuth::Builder do
provider :mystrategy, ENV["OAUTH_ID"], ENV["OAUTH_SECRET"],
:setup => lambda{|env|
env['omniauth.strategy'].options[:client_options].site = env['rack.session']['oauth_site']
}
end
One option is don't do it that way.
I have a similar app and ran into the same issue. However after thinking about it for a moment I realised that I didn't want to send them to a strategy provider URL on the user account's subdomain because the request wasn't yet fully authenticated (it hasn't been processed by the rails app yet).
Also for the first time a user logs in the user account subdomain hadn't yet been set up, so it would have been impossible to route there.
So instead, I have the strategy callback URL set to the main website. After the signin request is processed, session set up and everything, then I redirect the client onto their user subdomain. Takes out a whole load of pain.

Change Omniauth authorization URL

I'm using Omniauth with Devise using the google_oauth2 strategy.
It works well, but now I'd like to change the authorize path with something of my choice.
Actually it's http://localhost:3000/users/auth/google_oauth2 while I'd like a much simpler http://localhost:3000/login since it's simple to remember.
It would not raise any error since I've disabled the Devise database authenticable (the only way to login is through a google account).
How can I do?
Thanks.
You can see how to change url prefix here How to change route of omniauth from /auth/:provider to /myapp/auth/:provider
So it is almost what you need.

Resources