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/Controllers/OnboardingController.cs
+31-13Lines changed: 31 additions & 13 deletions
Original file line number
Diff line number
Diff line change
@@ -54,6 +54,8 @@ public IActionResult SignUp()
54
54
returnView();
55
55
}
56
56
57
+
/// <summary>This action builds the admin consent Url to let the tenant admin consent and provision a service principal of their app in their tenant.</summary>
Uri.EscapeDataString(azureADOptions.ClientId),// The application Id on Azure Portal
84
-
Uri.EscapeDataString(currentUri+"Onboarding/ProcessCode"),//Uri that will get redirected after the admin has consented
85
-
Uri.EscapeDataString(stateMarker),// The state parameter is used to validate the response, preventing a man-in-the-middle attack, and it will also be used to identify the entity on ProcessCode action.
86
-
Uri.EscapeDataString("https://graph.microsoft.com/.default"));// The scopes to be presented to the admin. Here we are using the static scope /.default.
86
+
Uri.EscapeDataString(azureADOptions.ClientId),// The application Id as obtained from the Azure Portal
87
+
Uri.EscapeDataString(currentUri+"Onboarding/ProcessCode"),// Uri that the admin will be redirected to after the consent
88
+
Uri.EscapeDataString(stateMarker),// The state parameter is used to validate the response, preventing a man-in-the-middle attack, and it will also be used to identify this request in the ProcessCode action.
89
+
Uri.EscapeDataString("https://graph.microsoft.com/.default"));// The scopes to be presented to the admin to consent. Here we are using the static scope '/.default' (https://docs.microsoft.com/azure/active-directory/develop/v2-permissions-and-consent#the-default-scope).
87
90
88
91
returnRedirect(authorizationRequest);
89
92
}
90
93
91
-
// This is the redirect Uri for the admin consent authorization
/// This handler is used to process the response after the admin consent process is complete.
96
+
/// </summary>
97
+
/// <param name="tenant">The directory tenant that granted your application the permissions it requested, in GUID format..</param>
98
+
/// <param name="error">An error code string that can be used to classify types of errors that occur, and can be used to react to errors..</param>
99
+
/// <param name="error_description">A specific error message that can help a developer identify the root cause of an error..</param>
100
+
/// <param name="admin_consent">Will be set to True to indicate that this response occurred on an admin consent flow..</param>
101
+
/// <param name="state">A value included in the request that also will be returned in the token response. It can be a string of any content you want. The state is used to encode information about the user's state in the app before the authentication request occurred, such as the page or view they were on..</param>
102
+
/// <remarks>Refer to https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-admin-consent for details on the response</remarks>
> :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.
181
+
> :warning: If you had onboarded your tenant using this sample in the past and now getting the **AADSTS650051** error when onboarding again, please refer to the [Error AADSTS650051](#error-aadsts650051) section below to mitigate this error.
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
-
### Service principle provision for new tenants (onboarding process)
218
+
### Service principle provisioning for new tenants (onboarding process)
219
219
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.
220
+
For a multi-tenant app to work across tenants, its service principle will need to be provisioned in the users' tenant. It can either happen when the first user signs in, or most tenant admins only allow a tenant admin to carry out the service principle provisioning. For provisioning, we will be using the [admin consent endpoint](https://docs.microsoft.com/azure/active-directory/develop/v2-admin-consent) for the onboarding process. The code for this is provided in the `OnboardingController.cs`. The `Onboard` action and corresponding view, simulate the onboarding flow and experience.
221
221
222
222
```csharp
223
223
[HttpPost]
@@ -236,13 +236,13 @@ public IActionResult Onboard()
236
236
}
237
237
```
238
238
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.
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, we create 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/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 that allows the tenant admin to consent for all permissions in one go. 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
244
244
245
-
On the `Startup.cs` we are calling `AddMicrosoftIdentityPlatformAuthentication` to configure the authentication, and it also validates that the token issuer is from AAD.
245
+
On the `Startup.cs` we are calling `AddMicrosoftIdentityPlatformAuthentication` to configure the authentication, and within that method, we validates that the token issuer is from AAD.
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.
286
+
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 separate the data of each tenant. In this sample, we have taken the single database approach to save the ToDo items for all users from all tenants.
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`has the 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
-
### Microsoft Graph token by tenant
290
+
### Acquiring Access token for Microsoft Graph for each 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 an access token for Microsoft Graph to be able to read data from the signed user's tenant, the token must be issued from their tenanted authority and not from the tenant where the SaaS 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();
296
-
// Acquiring token for graph using the user's tenantId, so it can return all the users from their tenant
296
+
// Acquiring token for graph using the user's tenant, so it can return all the users from their tenant
0 commit comments