{"id":7702,"date":"2021-09-20T12:04:25","date_gmt":"2021-09-20T19:04:25","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/microsoft365dev\/?p=7702"},"modified":"2021-10-18T10:46:59","modified_gmt":"2021-10-18T17:46:59","slug":"multi-tenant-architecture-for-saas-apps","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/microsoft365dev\/multi-tenant-architecture-for-saas-apps\/","title":{"rendered":"Multi-tenant architecture for SaaS apps"},"content":{"rendered":"<ul>\n<li>Do you distribute the same app to multiple clients\/tenants?<\/li>\n<li>Are you looking to offer <em>S<\/em><em>oftware as a service <\/em>and need to dig deep into the architecture of apps to work in multiple tenants?<\/li>\n<li>Are you tired of installing your app multiple times at these different clients\/tenants?<\/li>\n<li>Do you want to push updates like features and bug fixes into the app without any involvement of client&#8217;s IT admins?<\/li>\n<\/ul>\n<p><strong>Then you need to know about multi-tenancy and how you can create a multi-tenant app in Microsoft 365.<\/strong><\/p>\n<p>In this post, we will convert a simple single tenant JavaScript application into a multi-tenant app that can run across different tenants to bring data into the app. <strong>Same app, different data.<\/strong><\/p>\n<p>Check out our YouTube video for more guidance, live coding, and commentary \ud83d\udc47<\/p>\n<p style=\"text-align: center;\"><iframe title=\"YouTube video player\" src=\"https:\/\/www.youtube.com\/embed\/RjGVOFm39j0\" width=\"560\" height=\"315\" frameborder=\"0\" allowfullscreen=\"allowfullscreen\"><\/iframe><\/p>\n<p>Let&#8217;s first learn about single tenant apps. A single tenant app is registered and used in a single tenant (single instance). Here is the source code of a sample single tenant application that retrieves data from Microsoft 365 using Microsoft Graph: <a href=\"https:\/\/github.com\/MicrosoftDocs\/mslearn-retrieve-m365-data-with-msgraph-quickstart\" target=\"_blank\" rel=\"noopener\">https:\/\/github.com\/MicrosoftDocs\/mslearn-retrieve-m365-data-with-msgraph-quickstart.<\/a><\/p>\n<p>In the source code&#8217;s <a href=\"https:\/\/github.com\/MicrosoftDocs\/mslearn-retrieve-m365-data-with-msgraph-quickstart\/blob\/main\/README.md\">README file<\/a>, you can see that you&#8217;ll need to <strong>Register a new application in the Azure Portal<\/strong>. If you want to distribute, you&#8217;ll need to repeatedly register this app in each tenant to consume its services.<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/microsoft365dev\/wp-content\/uploads\/sites\/73\/2021\/09\/myappnotmytenant_single-tenant.png\"><img decoding=\"async\" class=\"aligncenter wp-image-7710 size-full\" src=\"https:\/\/devblogs.microsoft.com\/microsoft365dev\/wp-content\/uploads\/sites\/73\/2021\/09\/myappnotmytenant_single-tenant.png\" alt=\"Image myappnotmytenant single tenant\" width=\"480\" height=\"270\" srcset=\"https:\/\/devblogs.microsoft.com\/microsoft365dev\/wp-content\/uploads\/sites\/73\/2021\/09\/myappnotmytenant_single-tenant.png 480w, https:\/\/devblogs.microsoft.com\/microsoft365dev\/wp-content\/uploads\/sites\/73\/2021\/09\/myappnotmytenant_single-tenant-300x169.png 300w\" sizes=\"(max-width: 480px) 100vw, 480px\" \/><\/a><\/p>\n<p>So, what if you want to register once and use your app in multiple tenants? That&#8217;s what multi-tenant apps are for!<\/p>\n<p>Registering an app should not be confused with hosting. Hosting is where your app lives, which can be done anywhere. Registering your app is capturing it in the Microsoft identity platform, which can be done by <a href=\"https:\/\/docs.microsoft.com\/en-gb\/azure\/active-directory\/develop\/scenario-spa-app-registration?WT.mc_id=m365-41923-cxa\">registering the app in Azure AD<\/a> to consume Microsoft 365 services securely.<\/p>\n<h4><strong>Multi-tenant apps<\/strong><\/h4>\n<p>Applications that are registered only in a home tenant but used in home as well as in other tenants are called multi-tenant apps (multiple instances of the same app). Deploy once, use wherever. The app code remains the same, but the data will be different based on the tenant they are running in.<\/p>\n<p><img decoding=\"async\" class=\"aligncenter wp-image-6658 size-full\" src=\"https:\/\/officedevblogs.wpengine.com\/wp-content\/uploads\/2021\/09\/myappnotmytenant_multi-tenant.png\" alt=\"Image of app use in multiple tenant\" width=\"480\" height=\"270\" \/><\/p>\n<h4><strong>Convert a single tenant app to a multi-tenant app<\/strong><\/h4>\n<p>Let&#8217;s now go back to the sample app <a href=\"https:\/\/github.com\/MicrosoftDocs\/mslearn-retrieve-m365-data-with-msgraph-quickstart\">https:\/\/github.com\/MicrosoftDocs\/mslearn-retrieve-m365-data-with-msgraph-quickstart<\/a> which displays the name of a currently logged-in user using Microsoft Graph.<\/p>\n<p>Register the app in AAD as specified in the instructions in the above project\u2019s <a href=\"https:\/\/github.com\/MicrosoftDocs\/mslearn-retrieve-m365-data-with-msgraph-quickstart\/blob\/main\/README.md\">README file<\/a> \u00a0 but under <strong>Supported account types<\/strong>, choose <strong>Accounts in any organizational directory (Any Azure AD directory &#8211; Multitenant)<\/strong>.<\/p>\n<p>In this app solution, open the <strong>auth.js<\/strong> file. You can see the MSAL configuration of this app. Read more about MSAL which is the authentication library used to acquire tokens from Microsoft Identity platform in-order to safely and securely authenticated users and access API services like Microsoft Graph. The config without any changes would look like below:<\/p>\n<pre class=\"lang: decode:true\">const msalConfig = {\u00a0\u00a0\u00a0 auth: {\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 clientId: '&lt;your client ID here&gt;',\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\r\nauthority: 'https:\/\/login.microsoftonline.com\/&lt;your directory ID here&gt;',\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\r\nredirectUri: 'http:\/\/localhost:8080'\u00a0\u00a0\u00a0 }};<\/pre>\n<p>Directory ID is the same as tenant ID.<\/p>\n<p>Change it to:<\/p>\n<pre class=\"lang: decode:true \">const msalConfig = {\u00a0\u00a0\u00a0 auth: {\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 clientId: '&lt;your client ID here&gt;',\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\r\nauthority: 'https:\/\/login.microsoftonline.com\/common',\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\r\nredirectUri: 'http:\/\/localhost:8080'\u00a0\u00a0\u00a0 }};<\/pre>\n<p>(You replaced your directory ID with common)<\/p>\n<p>And that&#8217;s the code change really! Your app should now be a multi-tenant app. When you run the app on the browser, no matter which tenant you log into, the app will ask you to consent to permissions, and once consented positively will retrieve data from Microsoft 365 using Microsoft Graph without any knowledge of what tenant&#8217;s data it is accessing.<\/p>\n<h4><strong>What happens behind the scenes?<\/strong><\/h4>\n<p>When the app is registered under <strong>App registrations<\/strong> in AAD of the home tenant, an instance of the app is created called a <a href=\"https:\/\/docs.microsoft.com\/en-us\/azure\/active-directory\/develop\/app-objects-and-service-principals?WT.mc_id=m365-41923-cxa\">Service principal,<\/a> which is the <em>global<\/em> instance of the app object.<\/p>\n<p>These service principals or instances are created in all the tenants where the app is used. This enables the application to access services after authenticating the users successfully.<\/p>\n<p>When the app is accessed by client tenant&#8217;s users for the very first time, the app will register itself and create the service principal under <strong>Enterprise applications<\/strong> of the client&#8217;s tenant, creating the <em>local<\/em> instance of the app object. The registration at this level is seamless, and users or admins do not have to do anything besides consenting the app to permissions that it needs and can then access and use the application.<\/p>\n<p>Hope that demystifies the concept of multi-tenant applications in Microsoft 365! Read more about <a href=\"https:\/\/docs.microsoft.com\/en-us\/azure\/active-directory\/develop\/single-and-multi-tenant-apps?WT.mc_id=m365-41923-cxa\">Single tenant vs Multi-tenant apps here<\/a> and <a href=\"https:\/\/docs.microsoft.com\/en-us\/azure\/active-directory\/develop\/active-directory-how-applications-are-added?WT.mc_id=m365-41923-cxa\">about application in Azure AD here.<\/a><\/p>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Learn how to convert a simple single tenant JavaScript application into a multi-tenant app that can run across different tenants to bring data into the app. Same app, different data.<\/p>\n","protected":false},"author":71938,"featured_media":7709,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[3],"tags":[22],"class_list":["post-7702","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-microsoft-graph","tag-azure-ad"],"acf":[],"blog_post_summary":"<p>Learn how to convert a simple single tenant JavaScript application into a multi-tenant app that can run across different tenants to bring data into the app. Same app, different data.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/microsoft365dev\/wp-json\/wp\/v2\/posts\/7702","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/microsoft365dev\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/microsoft365dev\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/microsoft365dev\/wp-json\/wp\/v2\/users\/71938"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/microsoft365dev\/wp-json\/wp\/v2\/comments?post=7702"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/microsoft365dev\/wp-json\/wp\/v2\/posts\/7702\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/microsoft365dev\/wp-json\/wp\/v2\/media\/7709"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/microsoft365dev\/wp-json\/wp\/v2\/media?parent=7702"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/microsoft365dev\/wp-json\/wp\/v2\/categories?post=7702"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/microsoft365dev\/wp-json\/wp\/v2\/tags?post=7702"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}