Monday, 13 January 2020

Building a Multi-tenant Microsoft 365 App Part 1: Authorisation & Authentication


In this series , I'll talk about building a standalone web app that connects to some of your Microsoft 365 workloads, as an example we will assume that we are building a Mutli-tenant app that connects to Azure AD, SharePoint and Planner.

In this post I'll focus on one fundamental part which is authorisation&authentication. From an architectural standpoint we don't have a lot of options to assess specially if we are looking to use some of the existing platform capabilities
  1. Use Azure AD as your main Authentication/Authorisation provider , to get more details about how please read my detailed previous post(http://www.sharepointtweaks.com/2019/11/protecting-your-webapi-using-azure-AD.html)  in which I explained how to use Azure AD to not only connect to existing Microsoft Graph APIs but I also used it to protected a custom API I've built.
  2. The second important thing to consider is permission scope elevation. In other words, when requesting permissions you should start with least privileged set. This is not only a good user experience but it will allow you to  provide partial functionality to normal users even if your full app functionality requires an admin consent. An example, if your app is trying to get users images, it will require Read.Users.All scope which needs an admin consent. If you try to request this scope the app will keep showing the users that it requires admin consent which will make it not usable at all. 
    The solution to this problem could be very simply, don't initially request the scopes that requires admin consent until an admin "configures" your app. The trick would be how you can make sure that your app is configured without risking requesting some write permission to the directory which will make the admin very reluctant to try out your app.  You can do this by creating a configuration record in your app metadata (you can store this configuration anywhere Cosmos DB or even Azure Storage Table), This configuration record can be created as part of multi-step process in which you can ask the admin manually to consent to the add and maybe throwing a button to ease the process. You can simply assume that the admin has configured the app correctly so when your app loads app it checks if there is configuration record it requests the full set of scopes.
  3. The other challenge is how your app would tell whether the current user is an admin or not. This indeed is a tricky one, if you rely on user claims and given that the user could be a member of a lot of groups. Group associations won't appear as part of the token claims . You will require to query user groups maybe multiple times to just check whether the current user is and admin or not. 
    In my case I used a very simplistic approach. I used Azure AD app Roles, I've created a single App Role called "Admin" and I've asked the Microsoft 365 admin to add himself and maybe other people to this group and by adding the attribute  [Authorize(Roles = "Admin")] I can make sure that this endpoint is only available for users with Admin roles.  The drawback of this approach is you have to use direct user/role associations unless the organisation has P1 or P2 Azure AD license.
  4. Using Client-Side Authentication Library like MSAL will definitely make your life easier to implement authentication including login, token acquisition and token refresh. If you are using MSAL within a single page app it might be a bit challenging, if you want to read more about some issues with msal and SPA you can get an idea reading this github issue https://github.com/AzureAD/microsoft-authentication-library-for-js/issues/697  

This would be a wrap for this post, in part 2 we will discuss how to do logically or physically partition tenant data along with some challenges that comes with an easy to provision cloud storage vs. associated consumption cost.

Related Articles

0 comments:

Post a Comment