Tech

Setup Azure AD OAuth 2.0 with Ruby on Rails and Devise

Frantisek profile picture

Frantisek

My name is Frantisek and I am a committed engineer @PerAngusta. I came across multiple tutorials explaining how to setup an OAuth 2.0 connexion between Rails and Microsoft Azure AD.

They were all implementing pretty much the same. Unfortunately, none of them explained things deeply enough for a junior developer to understand. Thus, this article is a step-by-step guide of OAuth 2.0 authentication setup with Rails and Devise!

TLDR: there are two parts in this guide. For more technical explanation of what is OAuth 2.0 and how it works, scroll down to the end of the article

Photo by iMattSmart on Unsplash

Part 1 — Setting up Azure AD

Of course, for this whole guide to work, you need a configured tenant in Azure AD. Then, let’s begin!

First of all we need to register a new app in your tenant Azure Active Directory For this go to your Azure portal and click on “App registration” and on “New registration”.

Then you may fill 3 things and click to Register:

  • your Rails app name
  • the Supported account types option to “Single tenant”
  • Redirect URI to “Web” and https://example.com/users/auth/azure_activedirectory_v2/callback

For localhost testing, you may use something like http://localhost:3000/users/auth/azure_activedirectory_v2/callback. The redirect URI importance will become crystal clear when Rails is set up.

You app is now registered. Your app has been granted some IDs. Keep the Application (client) ID and Directory (tenant) ID somewhere safe! We will need it later on.

The last thing we need is to setup a secret-key for our app. For this, go to Certificates & secrets (obvious isn’t it?).

A secret string that the application uses to prove its identity when requesting a token.

Click on New client secret and follow the instructions. You only need to supply a Description and choose an expire strategy. For the latest, I would recommend to use the shortest period you can (here it is one year). Once it is generated you may copy it to clipboard or somewhere else. We will need it later too.

That’s it for Azure AD. 🚀

Part 2 — Setting up Rails

Now we can move to my Rails app and write some code! I suppose you have an app up and running. If you want to try this from scratch, feel free to use the Le Wagon template shipped with Devise.

First of all we need to add the gem we are going to use for this in the Gemfile and run bundle install .

EDIT: I have changed the gem because the original one seems not to be maintained anymore.

# Gemfile
gem 'omniauth-azure-activedirectory-v2'

Second we have to enable OmniAuth in Devise initialization and set it up on the User model. Here we are going to use the 3 informations we have kept safe from the first part and add them all to the .env file using the correct syntax.

# config/initializers/devise.rb
Devise.setup do |config|
  # Add this line
  config.omniauth :azure_activedirectory_v2,
                  client_id:     ENV['AZURE_CLIENT_ID'],
                  client_secret: ENV['AZURE_CLIENT_SECRET'],
                  tenant_id:     ENV['AZURE_TENANT_ID']
end

# app/models/user.rb
class User < ApplicationRecord
  # Add this line
  devise :omniauthable, omniauth_providers: %i[azure_activedirectory_v2]

  # ...
end

Third, we need to enable routes for devise OmniAuth functionality. That is where the Redirect URI gets created.

# config/routes.rb
Rails.application.routes.draw do
  # ...
  devise_for :users,
             controllers: {
               sessions:           'users/sessions',
               omniauth_callbacks: 'users/omniauth_callbacks'
             }
end

Now the routes are created, we implement a button in the frontend that triggers the new devise OmniAuth authorization API. It can be as simple as:

# config/routes.rb
<%= link_to "Log in with Azure AD",
            user_azure_activedirectory_v2_omniauth_authorize_path,
            class: 'btn btn-outline-primary btn-lg btn-block' %>

Fifth, we have to create the controller to which the response is going be sent. If you do not have it yet, you should create it.

# app/controllers/users/omniauth_callbacks_controller.rb
class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
  def azure_activedirectory_v2
    response_params = request.env['omniauth.auth']['info']
    @user = User.find_by!(email: response_params['email'])

    if @user&.persisted?
      sign_in_and_redirect @user, event: :authentication
    else
      flash[:danger] = 'You have not yet an account!'
      redirect_back(fallback_location: root_path)
    end
  end
end

Finally, we can test it and enjoy! 🚀

What the hell is OAuth 2.0?

OAuth 2.0 is the industry-standard protocol for authorization. OAuth 2.0 focuses on client developer simplicity while providing specific authorization flows for web applications, desktop applications, mobile phones, and living room devices.

Surprisingly, I have found the Microsoft documentation clear enough to understand. 😆 If you want to see a neat explanation about OAuth 2.0, check out this brilliant talk given by Halil at Lyon.rb (only in 🇫🇷 sorry)! Halil is one of our former interns @PerAngusta.

Feel free to join our Ruby community! We would be happy to meet you at our next meet-up, talking about Ruby and more!

Setup I have implemented it with:

ruby -> 2.6.5
rails -> 6.0.3.2
devise -> 4.2
omniauth-azure-activedirectory-v2  -> 1.0.0