While @google emails are popular among tech startups, most corporations use Microsoft to manage their employees email addresses. These companies often want to enable their employees to single-sign-on to work-related services with their Microsoft account.

Previously I’ve written about setting up omniauth with Github.

Now, let’s add a “Sign in with Microsoft” button:

microsoft-oauth-login-button.png

After clicking the button, the user will be prompted to authenticate with one of his Microsoft accounts:

microsoft-oauth-select-account.png

The approach is more-less similar for any omniauth provider. However I think the hardest part is navigating provider dashboards, getting valid API keys, registering your app, enabling the app in production 😬.

1. Get Microsoft oAuth API keys #

First, create a Microsoft Azure account and connect a credit card. When I created my account, I was granted ±200$ in credits for 1 year. That’s enough to experiement with the platform.

create microsoft azure account with free credits

Find and open “app registration”:

microsoft-omni-find-app-registration-1

Click “new registration”:

microsoft-omni-register-app-2

Input your app name;

Important: Select supported account types. When you are building a B2B app, often you will want to let only email accounts provided by an organization to access your app. This filters out some lurkers and spies.

Redirect URI for localhost should be http://localhost:3000/users/auth/azure_activedirectory_v2/callback

microsoft-omni-add-callback-3

Success! You’ve created an app! Now you see your client_id for omniauth:

microsoft-omni-application_client_id

Generate a client_secret. Copy the value.

microsoft-omni-application_secret_value

I suggest storing them in Rails credentials as:

microsoft_oauth:
  client_id: b810ccfa...
  client_secret: hGb8Q...

3. Configure your Rails app #

If you don’t want to use devise, see how to add omniauth without devise.

Here we assume that you already use Devise.

First, install the gem “omniauth-azure-activedirectory-v2”:

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

Add the generated API keys to your app:

# config/initializers/devise.rb
config.omniauth :azure_activedirectory_v2,
  client_id: Rails.application.credentials.dig(:microsoft_oauth, :client_id),
  client_secret: Rails.application.credentials.dig(:microsoft_oauth, :client_secret)

Afterwards, it’s the same process as for any other omniauth provider:

# app/models/user.rb
devise :omniauthable, omniauth_providers: [:azure_activedirectory_v2]
# config/routes.rb
devise_for :users, controllers: { omniauth_callbacks: 'users/omniauth_callbacks' }
rails g migration add_oauth_attributes_to_users provider uid
rails db:migrate
# app/controllers/users/omniauth_callbacks_controller.rb
class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
  def azure_activedirectory_v2
    data = request.env['omniauth.auth']['info']
    @user = User.where(email: data['email']).first
    @user ||= User.create(
      email: data['email'],
      password: Devise.friendly_token[0, 20],
      provider: request.env['omniauth.auth']['provider'],
      uid: request.env['omniauth.auth']['uid']
    )

    if @user.persisted?
      flash[:notice] = 'Welcome!'
      sign_in_and_redirect @user, event: :authentication
    else
      flash[:alert] = I18n.t 'Authentication failed, please try again.'
      redirect_to new_user_registration_url, notice: @user.errors.full_messages.join("\n")
    end
  end

  def failure
    redirect_to root_path, alert: 'Authentication failed, please try again.'
  end
end
# app/views/devise/shared/_links.html.erb
<%= button_to "Sign in with #{OmniAuth::Utils.camelize(provider)}", omniauth_authorize_path(resource_name, provider), method: :post, data: { turbo: "false" } %>

4. Troubleshooting #

If you get an unauthorized_client error, most likely the “supported account types” that you selected for your App registration don’t include your current account type.

To update it:

  1. In the sidebar, select Manifest.
  2. In the JSON code, find the signInAudience setting.
  3. Check whether the setting contains one of the following values:
    • AzureADMyOrg
    • AzureADMultipleOrgs
    • AzureADandPersonalMicrosoftAccount
    • PersonalMicrosoftAccount
  4. Select the scope you need and Save.

That’s it!