devot logo

How to Implement Sign In With Microsoft Using the Office 365 OmniAuth Strategy With Rails 7

How to Implement Sign In With Microsoft Using the Office 365 OmniAuth Strategy With Rails 7

Karlo A

Karlo A.

7 minutes

May 13, 2022

Link copied!

How to Implement Sign In With Microsoft Using the Office 365 OmniAuth Strategy With Rails 7

Whilst scrolling through the world wide web, have you ever encountered buttons with titles such as “Sign in with ‘X' service”? Well, those are there for a reason, and their purpose is to make your, and the developer’s life easier. Much easier. Let me explain why.

Back in the early days of web development, for a user to sign in and create a user session, they had to authorize themselves via their credentials - mainly their email and password. All users, and their corresponding credentials, were stored on a backend server and used to compare form-given credentials to authorize the user and grant them a session. That way, a user was authorized and could proceed to access the website. However, due to safety reasons and maintenance issues, using this kind of user authorization scheme has been proven to be bad practice nowadays.

One big concern during those times had been exposing user credentials to external services. Before the appearance of OAuth, in order to use an external service, a user had to provide their credentials to that service, which in turn would allow the service to perform certain actions on the user’s behalf.

Think of it this way - you’re a user, and the year is 2007. You’ve signed up to a new website, but now that website wants you to share your thoughts and experiences with people outside that website’s domain. In this case, it wants to use an external service like Gmail. The website asks for your Gmail address and password so it can log into your account and send emails to all of your contacts. Afterward, the website promises to forget your password and never use it again. Would you trust such a claim?

Yeah, neither would I. OAuth was developed to avoid such security risks. Generally, all OAuth does is redirect you to the domain of the external service upon which you are asked to authorize yourself. In short, instead of allowing a random website to obtain your user information for an external service, you are authorizing yourself via that external service using their domain. Short, simple, and safe, just how we like it. On another note, as proof of successful user authorization, OAuth provides you with an access token allowing access to the website’s API service.

OAuth

How to Easily Set up an External Authorization Procedure

This blog post is going to demonstrate how you can implement the “Sign in Microsoft” button with its full functionality by using Ruby 3.0.0 and Rails 7.0.2. Setting up an external Microsoft authorization prompt uses the same OAuth approach as explained above. In this case, OmniAuth is the gem that will be used for multi-provider OAuth authentication. We have to use the Microsoft Office OmniAuth strategy (gem) to implement it. The following is everything needed for the task:

Adding the CSRF protection gem is necessary for being able to mitigate issues with Cross-Site Request Forgery on the request phase when using the OmniAuth gem with a Rails application.

The next important step is registering a new Microsoft application from which we can get a Client ID and Client Secret. That can be done in the Microsoft Azure portal.

Before returning to the application side, make sure to set the homepage URL and callback URL on the Azure portal side. The homepage URL is the default server that is used when you run rails server, which in this case is: http://localhost:3000. The callback URL is where the office strategy is directed after the authentication process, whether or not the user passes the authentication. In our case, it will be set to: http://localhost:3000/auth/microsoft_office365/callback

The Client ID (Application ID), and the Client Secret (Application Secret) are used to validate and recognize requests that are coming from your application. They’re linked to the application side and, as such, will be saved as environment variables (this is why the 'dotenv-rails' is being used):

Once the authorization server has been set up, our application will accept requests and redirect towards the Microsoft OAuth strategy. For user authentication on the application’s side, we use Devise, whose setup is well explained on the official Github page.

Since Devise is not initially fully compatible with Turbo (which is built into Rails 7 by default), some adjustments are needed to the Devise initializer config. The primary reason is that Turbo allows asynchronous page updates without writing JavaScript. This behavior blocks Devise from displaying flash messages which are a core part of Devise itself. The following configuration re-establishes the default Devise behavior by adding a custom Turbo class. Credit goes where it’s due, and one can easily follow a guide on how to use Devise with Hotwire & Turbo.js.

First, an update on how the error messages are being handled is required:

Afterward, the following have to be added to the devise initializer.

Now, Devise has been properly initialized to work with Turbo and Rails 7 fully. The authorization application has also been set up with the proper callback URL. The only thing left to do is add the button and the logic behind it and apply it to a real-world example.

Since we’re doing user authentication and authorization, we need users to begin with. Devise offers a great tool for generating everything we need for that: rails g devise user. Now, after that, we'll need two columns added to your users table so that a user can hold an 'uid' and a 'provider'. These we'll be populated once the office OmniAuth strategy has successfully authenticated a user.

To do so, make migration with: rails g migration add_oauth_support_to_users and add the following lines:

Run rails db:migrate.

In the User model, update the devise part of the code to look like this:

In the same file, we'll add a new method to deal with the callback data that the strategy will provide:

For the last step, we need to create a route for this. Since we’re doing with Devise, the routes have already been implemented, but we need to intercept them to add the OmniAuth part of the logic. In the ‘routes.rb’ file, make sure to add the following:

For Devise to understand additional logic happening during the authentication process, we need to add our own controller, which looks like the following:

This flow creates a new user and saves the information in an instance variable ‘@user’. Next, if the user persisted in the external validation process, they’re signed in, and if not, they’re redirected to the registration page. That should be it, you should be ready to use your own “Sign in with Office365” button. 🙂

sign-in

Debugging

If OmniAuth decides not to cooperate with your project when dealing with raised exceptions after unsuccessful login attempts, try adding the following initializer, and it may aid the setting up process:

Wrap Up: How to Create a Fully Working “Sign in With Microsoft” Authorization Button

In order to be able to implement your own “Sign in with Microsoft” authorization button, you would need to do the following:

  • Include the OmniAuth gem in your project (along with the OmniAuth Office strategy, and other dependencies explained at the beginning of this post)

  • Setup your application via the Microsoft Azure portal

  • Retrieve your Application Key & Application Secret from the Azure portal, and save them on the Application side (preferably using a .env file)

  • Add required error message handling updates

  • Add required Devise initializer changes

  • Add database changes, configure callback methods, edit routes, add a custom controller for handling authorizations

There you go! A fully working "Sign in with Microsoft" authorization button that functions the same way as the ones you've seen everywhere online!

Now that you know this, you may have no issues implementing other OmniAuth strategies on your own. The premise stays the same:

  • Find the OmniAuth strategy you want to implement

  • Create a server side application using the strategy provider (i.e. Google, Facebook, Reddit, etc.)

  • Implement the authorization part on the application side

You're finished - it's as simple as that!

I’d personally advise trying to implement the Google authorization strategy next as it seems to be the simplest one to do. Give it a go, and I hope you make it through the challenge.