This blog is about SharePoint, Office365 and Office Development

Popular Posts

Building a Multi-tenant Microsoft 365 App Part 2: Data Partitioning

In this part we will discuss how we can partition different tenant data, in general you should have 2 types of data:
  1. Common Data that should live in a common data storage for this you can use a common database/Azure Storage account, example of this data is Tenant Configuration, admin data like invoicing and subscription status in case you've decided to make your app paid or freemium.
  2. Tenant Specific Data, In this case you can either go with logical segregation (using single azure storage account and use partitioning within the table) However, I'm always in favour of having a physical partitioning. This allows admin to choose data location upon registration. Your tenant registration will not only create some data configuration items in the common data store but it will also attempt to create a separate data store for the newly registered tenant. This can be achieved by adding a message to a storage queue which triggers an Azure Function which will provision the necessary artefact for each tenant.
The main two questions/concerns would be 
  1. Where shall I store access to these various storage accounts? and  
  2. How can i distinguish between tenant requests if I will be using the same services? (physical segregation for the API layer is an overkill and not necessary in my opinion)
The answers for the above questions are pretty simple. First you will need to store the keys for each tenant in a key store like Azure key Vault. For the second one we are very fortunate that tenantId is passed as part of the user claims and you can easily extract it from the claims using the below line of code. 
You can use the tenantId to locate your tenant record , get the tenant storage account key from Azure Key Vault then once you get a reference to the tenant storage account you can do the operation you desire.

Very Important: Don't rely on the client app to send the tenant Id , always get it from the user claims 

In the following parts I'll address some of the concerns that I've faced and how I overcome them, I'm keen to hear your thoughts some of the ideas are pretty basic and I'm open for more sophisticated approaches:
  1. What you shall do when a user decided to delete the registration?  The answer is do you want to keep the organisation data for a while so the admin can restore the data specially if the deletion was by mistake.
  2. What shall I do for data backup and storage account tiers? You can include the storage tier in your tenant registration tiers for example if you offer a free/Basic tier you can use LRS for a higher tiers you can GRS option.
  3. How can my client App access my tenant blob files?  the need for this might arise if you store some static files for each tenant blob and you need you client app to access these files (custom logos/custom images etc..) one easy way is to use a shared access signature another way is to allow your Azure AD to control access to your blob storage.
  4. How can I stop users from abusing the shared storage?  as far as I know and until the time I've last checked (couple of weeks back) I know that there is no storage quota limit per storage account or per blob container. What I was successful to do is to get used capacity per storage account using Azure monitor client this is of course a delayed result but you can get the updated value then store it in your tenant record and always check if the each tenant still have available quota or not. Of course your decision will be delayed as it rely on Azure monitor metric but better than nothing.

In  a nutshell this is a very basic multi-tenant application that uses the simplest form of storage (Azure Storage Account) to segregate each tenant data in a separate physical container if your app is more complex you can use other storage options like cosmos db.

In the Next post I'll go through the simplest method to hook up a payment gateway like stripe to your application.