Integrate Azure AD with Firebase and call MS Graph in a Node.js app
Tags: azure, security, webdev
Published: 2020-10-28 01:56:10

Today was the first day of Firebase Summit. Although not my default "go-to" technology for building apps, I always try to stay ahead of the curve and keep my self up-to-date with the latest and greatest in the software development space. And since Microsoft Identity permeates so many languages, technologies and platforms, I want to ensure that we have a good story for our developers. 

So today, my curiosity got the best of me, and after watching the session on Firebase authentication, I decided to go ahead and implement a custom authentication provider in Firebase. I, yes you guessed it, wanted to integrate Azure Active Directory to authenticate users and call MS Graph to get user profile and email data using the `Firebase.Auth` service.

In case you haven't heard or used Firebase before, Firebase is a collection of services such as auth, storage, messaging etc that you can use to build apps (mobile, web etc) on top of. You can find more information in the [official docs](https://firebase.google.com/).And as we know, there is very little you can do without touching authentication. Firebase offers a number of authentication options, including custom providers. This is a great opportunity to show how you can integrate Azure Active Directory with Firebase to authenticate users.

##Download and run the code
The working sample is available on [GitHub](https://github.com/cmatskas/javascriptWithFirebaseAndAAD) to clone and run locally. If you want to understand how the app was put together, you can use the included **Code Tour** to step through my code changes. [Code Tour](https://marketplace.visualstudio.com/items?itemName=vsls-contrib.codetour) is a VS Code extension to record and add explanations/annotation in your code to help others understand what you build.

## Create your Firebase project and app
There are three things we need to do to enable Firebase to work with Azure AD, before writing any code. 
- Create a Firebase project 
- Register an app in Firebase. 
- Register an app in Azure AD

We can complete these 3 tasks following the official docs (Firebase and Azure AD)

To create a new Firebase project, if you don't have one, go to your dashboard and click on the **Add project** button. 

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/ko7lgbcty032qt2c79as.jpg)

Give the project a meaningful name:

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/dhnuaflbtoihunhkprvu.jpg)

Press Continue on the next screen and on the final step, select a Google Analytics account to use for logging. Finally, press the **Create project** to finalize the project creation

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/16l42cakmrk2jaynmrde.jpg)

Step 1 done, 2 to go.

Next, we need to add an app to get started. The app indicates our intent to use Firebase and its underlying services. On the project we just created, we need to click on the appropriate platform to add the app. In this instance, we will be working on a web app, so let's go ahead and create it:

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/w9p92nm7v1bg9g8nfrp4.jpg)

On the next screen, give it a name and press Create. This will register the app and provide us with the the necessary configuration to instantiate the Firebase client in our code later. I love how it generates everything I need in one place!

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/c2nzf85nehwdr8f6g9bo.jpg)

Step 2 done, 1 (and a bit) to go.

For users to be able to authenticate against Azure AD, we also need to create an app registration in Azure AD. Let's head over to the Azure portal and create a new one. In the Azure AD portal, select the **App registrations** blade and hit the **New registration** button

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/dbijy0g2qsdis4esksdi.jpg)

Let's give our app a meaningful name, I chose `FirebaseAuth` and press the **Register** button. Next, we need to head to the **Certificates & secrets** blade to create a new secret. This secret will be used by Firebase to authenticate against AAD. 

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/z8vf0v241i82clixvm6t.jpg)

Make sure to copy the secret. Now, let's take a small diversion and head back to our Firebase dashboard to configure our custom Authentication with Azure AD. Click on the **Authentication** option on the navigation bar, select the **Sign-in method** and click on Microsoft to configure the Azure AD settings.

On the new popup window, paste the Azure AD application Id and secret we created in the steps above. Make sure to toggle the "Enable" to true so that you can edit the settings. Next, copy the **redirect URL** so that we can finalize the Azure AD app registration with the right information. 

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/gf44nyduz2m5va9mgzgw.jpg)

Let's hop back to our Azure AD app registration in the Azure portal to finalize the configuration. Head to the **Authentication** blade and press the **Add a platform**. 

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/ewoc70juigridbsqgmat.jpg)

In the **Redirect URIs**, add the URI that was provided in our Firebase configuration and press **Configure**. Unlike using a *normal* redirect URI, like `http://localhost:<port>` with this URI we instruct Azure AD to redirect the successful logins back to Firebase first, before returning the user back to the app. 

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/ppmibscg1x7p9pska7fz.jpg)

The last (optional) step is to add any extra permissions to our app registration. This is required if you need to speak to another custom API (maybe your API?), Azure service, MS Graph etc. Let's head over to the API permissions and add an extra Graph permission to request access to the user's emails. Open the **API Permissions** blade and click on the **Add a permission** button. Select MS Graph on the new tab.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/u3lts48s9whevqt1j4vw.jpg)

Next, select **Delegated permissions**, search for `Mail.Read`, select the permission and click the **Add permissions** button.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/com02jn2fy9r8bfnxpjm.jpg)

With this last step, our configuration is over and we can start writing some code.

## Create the Node.js app
Instead of trying to create something from scratch, I decided to download one of our quick start samples from AAD and convert it to use Firebase - simples :)

You can find a very large number of samples in our Azure AD docs, but there is also another, often overlooked, place that can help you get started. Inside the Azure AD app registration, open the **Quickstart** blade and select the technology you wish to work with:

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/sml990rn1tch56hi9vhe.jpg)

Since I want something as barebones as possible, I went with **Single-page application (SPA)** -> **JavaScript (auth code flow)**

On the next step, ignore the settings and click on the **Download the code sample**. Unzip and open in your favorite code editor. I work with VS Code in this instance. 

Next, we need to add a new file to handle the Firebase authentication. In the `app` folder, add `firebaseAuth.js`. In this file we will configure the `signIn`, `signOut` and calls to MS Graph. I know, not the best or cleanest design, but it does the job. Open the file and add the following code:

```
let firebaseConfig = {
    apiKey: "<your API Key>",
    authDomain: "<your domain>.firebaseapp.com",
    databaseURL: "https://<your domain>.firebaseio.com",
    projectId: "<your project name>",
    storageBucket: "<your domain>.appspot.com",
    messagingSenderId: "00000000000",
    appId: "1:549489080000:web:0000f4d2211ad0710219e7",
    measurementId: "G-11111G97CMT"
  };
  // Initialize Firebase
  firebase.initializeApp(firebaseConfig);
  firebase.analytics();

let provider = new firebase.auth.OAuthProvider('microsoft.com');
// set the persistence to session
// firebase.auth().setPersistence(firebase.auth.Auth.Persistence.SESSION);
let accessToken = '';

provider.setCustomParameters({
    tenant: 'b55f0c51-61a7-45c3-84df-33569b247796',
});

// this is required for Graph
provider.addScope('mail.read');

function signIn(){
    firebase.auth().signInWithPopup(provider)
        .then(function(result){
            showWelcomeMessage(result.additionalUserInfo.profile.displayName);
            accessToken = result.credential.accessToken;
            console.log('Authentication successful');
        })
        .catch(function(error) {
            console.log(`Error during authentication: ${error}`);
        });
}

function signOut(){
    firebase.auth().signOut().then(function() {
        // Sign-out successful.
        accessToken='';
        showSignOutMessage();
        console.log('user signed out');
      }).catch(function(error) {
        // An error happened.
        console.error('Sign out messed up somewhere...meh');
      });
}

function seeProfile(){
    callMSGraph(graphConfig.graphMeEndpoint, accessToken, updateUI);
    profileButton.classList.add('d-none');
    mailButton.classList.remove('d-none');
}

function readMail() {
    callMSGraph(graphConfig.graphMailEndpoint, accessToken, updateUI);
}
```

> Note: you can grab the Firebase config directly from your Firebase app registration, so don't worry about providing the individual details here, unless you know them.

The above code is called when we want to sign in our sign out users or get MS Graph data. It then calls the UI.js methods to update the UI accordingly. You can see the code in action below:

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/fr552ximv15gmlh0roev.gif)

You can play with some of the default settings to ensure that the signin/signout experience is tailored to your needs. For example, I changed how the auth state is persisted on the user's browsers once the user signs in. You can choose from `local, session, none`:

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/gvqcjpq3hi9or0es2k9h.jpg)

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/02g2l83e1fh0c8alsrnp.jpg)

##Conclusion
As you can see, integrating our existing identity provider, in this instance Azure AD, with Firebase is pretty straightforward. If you are a Firebase developer then the ability to add AAD as a custom identity provider opens up a lot of possibilities for building secure and rich aps that rely on open standards such as OAuth to keep your users safe while you focus on your business needs.