You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: 2-WebApp-graph-user/2-3-Multi-Tenant/README.md
+46-31Lines changed: 46 additions & 31 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -41,14 +41,14 @@ For more information about apps and tenancy, see [Tenancy in Azure Active Direct
41
41
42
42
## Scenario
43
43
44
-
This sample shows how to build a .NET Core MVC web application that uses the [OpenID Connect](https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-protocols-oidc) protocol to sign in users from multiple Azure AD tenants and acquire token for [Microsoft Graph](https://graph.microsoft.com) using the [Microsoft Authentication Library (MSAL)](https://docs.microsoft.com/en-us/azure/active-directory/develop/msal-overview). It leverages the ASP.NET Core OpenID Connect middleware.
44
+
This sample shows how to build a .NET Core MVC web application that uses the [OpenID Connect](https://docs.microsoft.com/azure/active-directory/develop/v2-protocols-oidc) protocol to sign in users from multiple Azure AD tenants and acquire token for [Microsoft Graph](https://graph.microsoft.com) using the [Microsoft Authentication Library (MSAL)](https://docs.microsoft.com/azure/active-directory/develop/msal-overview). It leverages the ASP.NET Core OpenID Connect middleware.
45
45
46
46
The application puts forward a scenario where a SaaS application invites the administrators of Azure AD tenants to `enroll` their tenants into this app. This process is analogous to a customer `buying` a SaaS product.
47
47
48
-
1. Once you start the application, you will land in the homepage where you can sign-in or onboard your tenant.
49
-
1. If you sign-in before onboarding your tenant, you'd land on a page with a heading **Unauthorized Tenant**. Click on the **Take me to the onboarding process** button to onboard your tenant to this application.
50
-
1. On the onboarding page, you will be asked to sign-in as an **administrator** and accept an **admin consent**for the application.
51
-
1. Once you have **registered your tenant**, all users from that tenant will be able to sign-in and explore the todo list.
48
+
1. Once you start the application, you will land on the homepage where you can **sign-in** or **onboard** your tenant.
49
+
1. If you try to **Sign-In** before onboarding your tenant, you'd land on the **Unauthorized Tenant** page. Click on the **Take me to the onboarding process** button to onboard your tenant to this application.
50
+
1. On the onboarding page, you will be asked to sign-in as a tenant **administrator** and accept the permissions requested in the **admin consent**screen to successfully provision the application in your tenant.
51
+
1. Once you have **registered your tenant**, all users from that tenant will be able to sign-in and explore the ToDo list.
52
52
53
53
> Looking for previous versions of this code sample? Check out the tags on the [releases](../../releases) GitHub page.
54
54
@@ -75,8 +75,6 @@ or download and extract the repository .zip file.
75
75
76
76
### Step 2: Register the sample application with your Azure Active Directory tenant
77
77
78
-
> :warning:**If you had created this sample in the past already**: [Delete its **enterprise app** from the other tenants before re-creating this application](#error-AADSTS650051).
79
-
80
78
There is one project in this sample. To register it, you can:
81
79
82
80
- either follow the steps [Step 2: Register the sample with your Azure Active Directory tenant](#step-2-register-the-sample-with-your-azure-active-directory-tenant) and [Step 3: Configure the sample to use your Azure AD tenant](#choose-the-azure-ad-tenant-where-you-want-to-create-your-applications)
@@ -134,7 +132,7 @@ As a first step you'll need to:
- In the **Advanced settings** section, set **Logout URL** to `https://localhost:44321/signout-oidc`.
137
-
- In the **Advanced settings** | **Implicit grant** section, check the **ID tokens** option as this sample requires the [Implicit grant flow](https://docs.microsoft.com/azure/active-directory/develop/v2-oauth2-implicit-grant-flow)to be enabled to sign-in the user, and call an API.
135
+
- In the **Advanced settings** | **Implicit grant** section, check the **ID tokens** option as the [AspNetCore security middleware](https://github.com/aspnet/AspNetCore/tree/master/src/Security) used in the sample uses the [Implicit grant flow](https://docs.microsoft.com/azure/active-directory/develop/v2-oauth2-implicit-grant-flow)by default to get the user info right after sign-in.
138
136
139
137
1. Click the **Save** button on top to save the changes.
140
138
1. In the app's registration screen, click on the **Certificates & secrets** blade in the left to open the page where we can generate secrets and upload certificates.
@@ -164,60 +162,62 @@ Open the project in your IDE (like Visual Studio) to configure the code.
164
162
### Step 4: Run the sample
165
163
166
164
Clean the solution, rebuild the solution, and run it.
167
-
The sample implements two distinct tasks: the onboarding of a new tenant and a basic Todo List CRUD operation.
165
+
The sample implements two distinct tasks: the onboarding of a new tenant and a basic ToDo List CRUD operation.
168
166
169
167
Ideally, you would want to have two Azure AD tenants so you can test the multi-tenant aspect of this sample. For more information on how to get an Azure AD tenant, see [How to get an Azure AD tenant](https://azure.microsoft.com/documentation/articles/active-directory-howto-tenant/).
170
168
171
169
#### Signing-in
172
170
173
-
Users can only sign-in if their tenant had been "onboarded". The sample will guide them how to do so, but it requires a **tenant admin account** to complete the onboarding process. Once the admin have consented, all users from their tenant will be able to sign-in.
171
+
Users can only sign-in if their tenant had been "onboarded" first. The sample will guide them how to do so, but it requires a **tenant admin account** to complete the onboarding process. Once the admin has consented and provisioned the app in their tenant, all users from their tenant will be able to sign-in.
174
172
175
173
If you try to onboard without an admin account, you will be presented with the following screen. Please switch to an admin account to complete this step:
176
174
177
-

175
+

178
176
179
-
If you try to sign-in with a tenant that haven't been "onboarded" yet, you will land in this page. Please click on **Take me to the onboarding process** button and follow the instructions to get your tenant registered in the sample database:
177
+
If you try to sign-in with a tenant that hasn't been "onboarded" yet, you will land on the following page. Please click on **Take me to the onboarding process** button and follow the instructions to get your tenant registered in the sample database:
> :warning: If you onboarded your tenant using this sample in the past already and getting the **AADSTS650051** error when onboarding again, please refer to the [Error AADSTS650051](#error-aadsts650051) section below.
182
+
183
+
#### ToDo List
184
184
185
-
Users from one tenant can't see todo items from other tenants. They will be able to perform basic CRUD operations on todo items assigned to them. When editing a todo item, users can assign it to any other user from their tenant. The list of users is coming from Microsoft Graph, using the [Graph SDK](https://github.com/microsoftgraph/msgraph-sdk-dotnet).
185
+
Users from one tenant can't see the **ToDo**items of users from other tenants. They will be able to perform basic CRUD operations on ToDo items assigned to them. When editing a ToDo item, users can assign it to any other user from their tenant. The list of users in a tenant is fetched from Microsoft Graph, using the [Graph SDK](https://github.com/microsoftgraph/msgraph-sdk-dotnet).
186
186
187
187
The list of users will be presented in the **Assigned To** dropdown:
188
188
189
-

189
+

190
190
191
191
## About The code
192
192
193
-
This sample covers the following topics on a multi-tenant app.
193
+
This sample details the following aspects of a multi-tenant app.
194
194
195
-
- usage of the `/common` endpoint
196
-
-service principle provision for new tenants
197
-
-custom token validation allowing only registered tenants
198
-
-data partition
199
-
- Microsoft Graph token by tenant
195
+
- usage of the `/common` endpoint.
196
+
-Service Principle provisioning of an app in Azure AD tenants
197
+
-Custom Token Validation to allow users from onboarded tenants only.
198
+
-Data partitioning in multi-tenant apps.
199
+
-Acquiring Access tokens for Microsoft Graph for each tenant.
200
200
201
-
It is using the OpenID Connect ASP.NET Core middleware to sign in users from multiple Azure AD tenants. The middleware is initialized in the `Startup.cs` file by passing it the Client ID of the app, and the URL of the Azure AD tenant where the app is registered. These values are read from the `appsettings.json` file.
201
+
This sample is using the OpenID Connect ASP.NET Core middleware to sign in users from multiple Azure AD tenants. The middleware is initialized in the `Startup.cs` file by passing it the Client ID of the app, and the URL of the Azure AD tenant where the app is registered. These values are read from the `appsettings.json` file.
202
202
203
203
You can trigger the middleware to send an OpenID Connect sign-in request by decorating a class or method with the `[Authorize]` attribute or by issuing a challenge (see the [AccountController.cs](https://github.com/aspnet/AspNetCore/blob/master/src/Azure/AzureAD/Authentication.AzureAD.UI/src/Areas/AzureAD/Controllers/AccountController.cs) file which is part of ASP.NET Core):
204
204
205
205
These steps are encapsulated in the [Microsoft.Identity.Web](..\..\Microsoft.Identity.Web) project, and in particular in the [WebAppServiceCollectionExtensions.cs](..\..\Microsoft.Identity.Web\WebAppServiceCollectionExtensions.cs) file
206
206
207
207
### Usage of `/common` endpoint
208
208
209
-
In order to be able to sign-in users from multiple tenants using OpenID Connect, the [/common endpoint](https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-protocols-oidc#fetch-the-openid-connect-metadata-document) must be used so Microsoft identity platform can fetch the metadata document. In the sample, this endpoint is used as a result of setting the value for `TenantId` as `organizations` on the `appsettings.json` file, and configuring the middleware to read the values from it.
209
+
In order to be able to sign-in users from multiple tenants, the [/common endpoint](https://docs.microsoft.com/azure/active-directory/develop/howto-convert-app-to-be-multi-tenant#update-your-code-to-send-requests-to-common) must be used. In the sample, this endpoint is used as a result of setting the value for `TenantId` as `organizations` on the `appsettings.json` file, and configuring the middleware to read the values from it.
Read more about [OpenID Connect endpoints here](https://docs.microsoft.com/en-us/azure/active-directory/develop/active-directory-v2-protocols#endpoints).
216
+
You can read about the various endpoints of the Microsoft Identity Platform [here](https://docs.microsoft.com/azure/active-directory/develop/active-directory-v2-protocols#endpoints).
217
217
218
218
### Service principle provision for new tenants (onboarding process)
219
219
220
-
On a multi-tenant app, its service principle will be created on all the users' tenants that have signed-in at least once. Some might want that only tenant admins accept the service principle provisioning. For that, we are using the [admin consent endpoint](https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-admin-consent) for the onboarding process on the `OnboardingController.cs`. The `Onboard` action and corresponding view, simulate an onboarding experience.
220
+
For a multi-tenant app, its service principle will be created on all the users' tenants that have signed-in at least once. Some might want that only tenant admins accept the service principle provisioning. For that, we are using the [admin consent endpoint](https://docs.microsoft.com/azure/active-directory/develop/v2-admin-consent) for the onboarding process on the `OnboardingController.cs`. The `Onboard` action and corresponding view, simulate an onboarding experience.
221
221
222
222
```csharp
223
223
[HttpPost]
@@ -238,7 +238,7 @@ public IActionResult Onboard()
238
238
239
239
This results in an OAuth2 code grant request that triggers the admin consent flow and creates the service principle in the admin's tenant. The `state` parameter is used to validate the response, preventing a man-in-the-middle attack. Then, the `ProcessCode` action receives the authorization code from Azure AD and, if they appear valid, it creates an entry in the application database for the new customer.
240
240
241
-
The `https://graph.microsoft.com/.default` is a static scope. You can find more about static scope on [this link.](https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-admin-consent#request-the-permissions-from-a-directory-admin)
241
+
The `https://graph.microsoft.com/.default` is a static scope. You can find more about static scope on [this link.](https://docs.microsoft.com/azure/active-directory/develop/v2-admin-consent#request-the-permissions-from-a-directory-admin)
242
242
243
243
### Custom token validation allowing only registered tenants
There are two common scenarios regarding data partition on a multi-tenant app. Having a separate database for each tenant or having a single database and using the **tenantId** to distinguish the data from each tenant. In this sample, we used the single database approach to save the todo items.
287
287
288
-
`TodoListController.cs` have basic CRUD actions for `TodoItem` and each operation takes into account the signed user's **tenantId** to separate data from each tenant. The tenantId can be found in the user' claims.
288
+
`TodoListController.cs` have basic CRUD actions for `todoItem` and each operation takes into account the signed user's **tenantId** to separate data from each tenant. The tenantId can be found in the user' claims.
289
289
290
290
### Microsoft Graph token by tenant
291
291
292
-
If a multi-tenant app needs to acquire a token from Graph to read data from the signed user's tenant, the token must be issued with their tenantId authority and not where the application is registered. This feature is being showed on the **Edit** action result on `TodoListController.cs`.
292
+
If a multi-tenant app needs to acquire a token from Graph to read data from the signed user's tenant, the token must be issued with their tenantId authority and not where the application is registered. This feature is being showed on the **Edit** action result on `todoListController.cs`.
293
293
294
294
```csharp
295
295
varuserTenant=User.GetTenantId();
@@ -312,7 +312,7 @@ AuthenticationResult result = await confidentialClientApplication
312
312
313
313
### Error AADSTS650051
314
314
315
-
If you are receiving the following error message, you might need to **delete older Enterprise Applications of this sample**
315
+
If you are receiving the following error message, you might need to **delete older service principals of this application**. Please [delete the existing [service principal](https://docs.microsoft.com/azure/active-directory/develop/app-objects-and-service-principals) from the **enterprise app** blade of the tenant before re-creating this application]. Click on the **Enterprise Applications** blade in the portal, locate this application `WebApp-MultiTenant-v2`, navigate to its **properties** and click **Delete** to delete the service principal.
316
316
317
317
> OpenIdConnectProtocolException: Message contains error: 'invalid_client', error_description: 'AADSTS650051: Application '{applicationId}' is requesting permissions that are either invalid or out of date.
318
318
@@ -325,10 +325,25 @@ If you'd like to contribute to this sample, see [CONTRIBUTING.MD](/CONTRIBUTING.
325
325
This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information, see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [[email protected]](mailto:[email protected]) with any additional questions or comments.
326
326
327
327
## Learn more
328
-
To understand more about token validation, see
328
+
329
+
To learn more about single and multi-tenant apps
330
+
331
+
-[Tenancy in Azure Active Directory](https://docs.microsoft.com/en-us/azure/active-directory/develop/single-and-multi-tenant-apps)
332
+
-[How to: Sign in any Azure Active Directory user using the multi-tenant application pattern](https://docs.microsoft.com/en-us/azure/active-directory/develop/howto-convert-app-to-be-multi-tenant)
333
+
-[Application and service principal objects in Azure Active Directory](https://docs.microsoft.com/en-us/azure/active-directory/develop/app-objects-and-service-principals)
-[Understanding Azure AD application consent experiences](https://docs.microsoft.com/en-us/azure/active-directory/develop/application-consent-experience)
339
+
-[Understand user and admin consent](https://docs.microsoft.com/en-us/azure/active-directory/develop/howto-convert-app-to-be-multi-tenant#understand-user-and-admin-consent)
-[Validating an id_token](https://docs.microsoft.com/en-us/azure/active-directory/develop/id-tokens#validating-an-id_token)
330
344
331
345
To understand more about app registration, see:
332
346
333
347
-[Quickstart: Register an application with the Microsoft identity platform (Preview)](https://docs.microsoft.com/azure/active-directory/develop/quickstart-register-app)
334
348
-[Quickstart: Configure a client application to access web APIs (Preview)](https://docs.microsoft.com/azure/active-directory/develop/quickstart-configure-app-access-web-apis)
Copy file name to clipboardExpand all lines: 2-WebApp-graph-user/2-3-Multi-Tenant/Views/Home/Index.cshtml
+5-5Lines changed: 5 additions & 5 deletions
Original file line number
Diff line number
Diff line change
@@ -6,22 +6,22 @@
6
6
}
7
7
8
8
<h1>
9
-
ASP.NET Core web app signing-in users in any Azure AD organization
9
+
A ASP.NET Core web app signing-in users from any Azure AD organization
10
10
</h1>
11
11
<p>
12
12
This sample shows how to build a .NET Core MVC Web app that uses OpenID Connect to sign in users. Users can use work and school accounts from any company or organization that has integrated with Azure Active Directory. It leverages the ASP.NET Core OpenID Connect middleware.
0 commit comments