Custom Domain Login in Ruby on Rails
Heertheeswaran V
Posted on September 23, 2020
Why Custom Domain?
Let’s take a scenario, in which an application https://app.example.org has to be accessed by multiple organizations (for instance, Org1 and Org2) with their own domain such as https://app.org1.org and https://app.org2.org. This can be achieved by introducing a custom domain (the domain in which the user wants to access the application) in the application.
To create a system with custom domain features, you have to maintain the session in a multi-domain environment. Handling sessions in this multi-domain environment is not simple, because the cookies are mapped to the domain to where it is set.
Setting up Custom Domain Session
Let’s take an example where the URL of the application is https://app.example.org and it has to be accessed with https://site.example1.org.
We will be using device authentication in this application. When we login with email and password there will be no confusion as the host is the same across all the actions. Also, the session was set by the domain accessed for the login. But, when we use omniauth logins such as Google or GitHub, there will be a difficulty as the callback URL can’t be set dynamically.
To overcome this difficulty, we follow the below-mentioned steps:
- Set the device’s default user authentication to ‘omniauth’ authentication
- In the callback action, redirect the custom domain (as Host) with a unique token (to identify the user) to the custom actions
- In the custom action, the user is identified and logged in to the custom domain
- Now, the session is set by the custom domain and the user can access the entire application
- Here, the application (app.example.org) acts as the base for many other mini-applications (site.example1.org, etc.,).
Let’s see the above steps in detail with google login as an example. Let’s say that the Google Auth Callback URL is app.example.org/users/auth/google_oauth2/callback.
Omniauth Origin
In Omniauth, we have a parameter in the request which gives the origin URL of the authentication process. Let’s say we have the Sign In With Google Button in the_ /user/sign_in action. If the user clicks it from _app.example.org/user/sign_in, then this parameter will be the URL. This will be available in the following key request.env['omniauth.origin']. With this, we can find the host/domain of the request.
Custom Domain Login in Practice
When the user login with the custom domain URL https://site.example1.org/user/signin
, the below Omniauth Callback action has to be performed:
- Authenticate the user in the Application Level (across the application).
- Find the Host from the Omniauth Origin. In this case, the host will be site.example1.org
URI.parse(request.env['omniauth.origin']).host)
- Redirect to the custom action with the host as omniauth origin, along with the unique token to identify the authenticated user. Let’s call this custom action as social_login. To identify the user, we will encrypt the email as the unique token (as a parameter). So the redirect URL can be generated as
"https://#{HOST}/user/social_login?key=#{user.encrypt_email}"
and the redirect URL will be “https://site.example1.org/user/social_login?key=encrypted_key”. - In the Social Login action, we can identify the user by decrypting the email which was received as the parameter in the above step. After identifying the user, we can sign in the user with the device sign_in function. Now, the user’s session will be tied to the custom domain.
def social_login
if params["key"].present?
@user = User.find_by(
email: User.decrypt(params["key"])
)
if @user.present?
sign_in @user
check_private_organizaiton
else
redirect_to root_path, notice: "Please try again!"
end
else
redirect_to root_path, notice: "Please try again!"
end
end
I hope this blog gives you an idea to maintain a session with a custom domain! Try it out and let me know what do you think at heerthees@skcript.com
Posted on September 23, 2020
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.