Skip to content

Commit 933f4f3

Browse files
authored
Blazor WASM security updates for 5.0 (#20147)
1 parent 12583b9 commit 933f4f3

12 files changed

Lines changed: 180 additions & 86 deletions

aspnetcore/blazor/security/webassembly/hosted-with-azure-active-directory-b2c.md

Lines changed: 13 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ description: Learn how to secure an ASP.NET Core Blazor WebAssembly hosted app w
55
monikerRange: '>= aspnetcore-3.1'
66
ms.author: riande
77
ms.custom: mvc
8-
ms.date: 07/08/2020
8+
ms.date: 10/08/2020
99
no-loc: ["ASP.NET Core Identity", cookie, Cookie, Blazor, "Blazor Server", "Blazor WebAssembly", "Identity", "Let's Encrypt", Razor, SignalR]
1010
uid: blazor/security/webassembly/hosted-with-azure-active-directory-b2c
1111
---
@@ -51,7 +51,7 @@ In **Expose an API**:
5151

5252
Record the following information:
5353

54-
* App ID URI (for example, `https://contoso.onmicrosoft.com/41451fa7-82d9-4673-8fa5-69eff5a761fd`, `api://41451fa7-82d9-4673-8fa5-69eff5a761fd`, or the custom value that you provided)
54+
* App ID URI (for example, `api://41451fa7-82d9-4673-8fa5-69eff5a761fd`, `https://contoso.onmicrosoft.com/41451fa7-82d9-4673-8fa5-69eff5a761fd`, or the custom value that you provided)
5555
* Scope name (for example, `API.Access`)
5656

5757
The App ID URI might require a special configuration in the client app, which is described in the [Access token scopes](#access-token-scopes) section later in this topic.
@@ -125,29 +125,21 @@ Replace the placeholders in the following command with the information recorded
125125
dotnet new blazorwasm -au IndividualB2C --aad-b2c-instance "{AAD B2C INSTANCE}" --api-client-id "{SERVER API APP CLIENT ID}" --app-id-uri "{SERVER API APP ID URI}" --client-id "{CLIENT APP CLIENT ID}" --default-scope "{DEFAULT SCOPE}" --domain "{TENANT DOMAIN}" -ho -o {APP NAME} -ssp "{SIGN UP OR SIGN IN POLICY}"
126126
```
127127

128-
| Placeholder | Azure portal name | Example |
129-
| ----------------------------- | ----------------------------------------------------- | -------------------------------------- |
130-
| `{AAD B2C INSTANCE}` | Instance | `https://contoso.b2clogin.com/` |
131-
| `{APP NAME}` | — | `BlazorSample` |
132-
| `{CLIENT APP CLIENT ID}` | Application (client) ID for the *`Client`* app | `4369008b-21fa-427c-abaa-9b53bf58e538` |
133-
| `{DEFAULT SCOPE}` | Scope name | `API.Access` |
134-
| `{SERVER API APP CLIENT ID}` | Application (client) ID for the *Server API app* | `41451fa7-82d9-4673-8fa5-69eff5a761fd` |
135-
| `{SERVER API APP ID URI}` | Application ID URI ([see note](#access-token-scopes)) | `41451fa7-82d9-4673-8fa5-69eff5a761fd` |
136-
| `{SIGN UP OR SIGN IN POLICY}` | Sign-up/sign-in user flow | `B2C_1_signupsignin1` |
137-
| `{TENANT DOMAIN}` | Primary/Publisher/Tenant domain | `contoso.onmicrosoft.com` |
128+
| Placeholder | Azure portal name | Example |
129+
| ----------------------------- | ----------------------------------------------------- | -------------------------------------------- |
130+
| `{AAD B2C INSTANCE}` | Instance | `https://contoso.b2clogin.com/` |
131+
| `{APP NAME}` | — | `BlazorSample` |
132+
| `{CLIENT APP CLIENT ID}` | Application (client) ID for the *`Client`* app | `4369008b-21fa-427c-abaa-9b53bf58e538` |
133+
| `{DEFAULT SCOPE}` | Scope name | `API.Access` |
134+
| `{SERVER API APP CLIENT ID}` | Application (client) ID for the *Server API app* | `41451fa7-82d9-4673-8fa5-69eff5a761fd` |
135+
| `{SERVER API APP ID URI}` | Application ID URI | `api://41451fa7-82d9-4673-8fa5-69eff5a761fd` |
136+
| `{SIGN UP OR SIGN IN POLICY}` | Sign-up/sign-in user flow | `B2C_1_signupsignin1` |
137+
| `{TENANT DOMAIN}` | Primary/Publisher/Tenant domain | `contoso.onmicrosoft.com` |
138138

139139
The output location specified with the `-o|--output` option creates a project folder if it doesn't exist and becomes part of the app's name.
140140

141141
> [!NOTE]
142-
> Pass the App ID URI to the `app-id-uri` option, but note a configuration change might be required in the client app, which is described in the [Access token scopes](#access-token-scopes) section.
143-
>
144-
> Additionally, the scope set up by the Hosted Blazor template might have the App ID URI host repeated. Confirm that the scope configured for the `DefaultAccessTokenScopes` collection is correct in `Program.Main` (`Program.cs`) of the *`Client`* app.
145-
146-
::: moniker range=">= aspnetcore-5.0"
147-
148-
[!INCLUDE[](~/includes/blazor-security/additional-scopes-hosted-nonAAD.md)]
149-
150-
::: moniker-end
142+
> The scope set up by the Hosted Blazor template might have the App ID URI host repeated. Confirm that the scope configured for the `DefaultAccessTokenScopes` collection is correct in `Program.Main` (`Program.cs`) of the *`Client`* app.
151143
152144
> [!NOTE]
153145
> In the Azure portal, the *`Client`* app's platform configuration **Redirect URI** is configured for port 5001 for apps that run on the Kestrel server with default settings.
@@ -354,8 +346,6 @@ Specify additional scopes with `AdditionalScopesToConsent`:
354346
options.ProviderOptions.AdditionalScopesToConsent.Add("{ADDITIONAL SCOPE URI}");
355347
```
356348

357-
[!INCLUDE[](~/includes/blazor-security/azure-scope.md)]
358-
359349
For more information, see the following sections of the *Additional scenarios* article:
360350

361351
* [Request additional access tokens](xref:blazor/security/webassembly/additional-scenarios#request-additional-access-tokens)

aspnetcore/blazor/security/webassembly/hosted-with-azure-active-directory.md

Lines changed: 93 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ description: Learn how to secure an ASP.NET Core Blazor WebAssembly hosted app w
55
monikerRange: '>= aspnetcore-3.1'
66
ms.author: riande
77
ms.custom: "devx-track-csharp, mvc"
8-
ms.date: 07/08/2020
8+
ms.date: 10/08/2020
99
no-loc: ["ASP.NET Core Identity", cookie, Cookie, Blazor, "Blazor Server", "Blazor WebAssembly", "Identity", "Let's Encrypt", Razor, SignalR]
1010
uid: blazor/security/webassembly/hosted-with-azure-active-directory
1111
---
@@ -52,7 +52,7 @@ In **Expose an API**:
5252

5353
Record the following information:
5454

55-
* App ID URI (for example, `https://contoso.onmicrosoft.com/41451fa7-82d9-4673-8fa5-69eff5a761fd`, `api://41451fa7-82d9-4673-8fa5-69eff5a761fd`, or the custom value that you provided)
55+
* App ID URI (for example, `api://41451fa7-82d9-4673-8fa5-69eff5a761fd`, `https://contoso.onmicrosoft.com/41451fa7-82d9-4673-8fa5-69eff5a761fd`, or the custom value that you provide)
5656
* Scope name (for example, `API.Access`)
5757

5858
The App ID URI might require a special configuration in the client app, which is described in the [Access token scopes](#access-token-scopes) section later in this topic.
@@ -119,24 +119,29 @@ In an empty folder, replace the placeholders in the following command with the i
119119
dotnet new blazorwasm -au SingleOrg --api-client-id "{SERVER API APP CLIENT ID}" --app-id-uri "{SERVER API APP ID URI}" --client-id "{CLIENT APP CLIENT ID}" --default-scope "{DEFAULT SCOPE}" --domain "{TENANT DOMAIN}" -ho -o {APP NAME} --tenant-id "{TENANT ID}"
120120
```
121121

122-
| Placeholder | Azure portal name | Example |
123-
| ---------------------------- | ----------------------------------------------------- | -------------------------------------- |
124-
| `{APP NAME}` | — | `BlazorSample` |
125-
| `{CLIENT APP CLIENT ID}` | Application (client) ID for the *`Client`* app | `4369008b-21fa-427c-abaa-9b53bf58e538` |
126-
| `{DEFAULT SCOPE}` | Scope name | `API.Access` |
127-
| `{SERVER API APP CLIENT ID}` | Application (client) ID for the *Server API app* | `41451fa7-82d9-4673-8fa5-69eff5a761fd` |
128-
| `{SERVER API APP ID URI}` | Application ID URI ([see note](#access-token-scopes)) | `41451fa7-82d9-4673-8fa5-69eff5a761fd` |
129-
| `{TENANT DOMAIN}` | Primary/Publisher/Tenant domain | `contoso.onmicrosoft.com` |
130-
| `{TENANT ID}` | Directory (tenant) ID | `e86c78e2-8bb4-4c41-aefd-918e0565a45e` |
122+
| Placeholder | Azure portal name | Example |
123+
| ---------------------------- | ----------------------------------------------------- | -------------------------------------------- |
124+
| `{APP NAME}` | — | `BlazorSample` |
125+
| `{CLIENT APP CLIENT ID}` | Application (client) ID for the *`Client`* app | `4369008b-21fa-427c-abaa-9b53bf58e538` |
126+
| `{DEFAULT SCOPE}` | Scope name | `API.Access` |
127+
| `{SERVER API APP CLIENT ID}` | Application (client) ID for the *Server API app* | `41451fa7-82d9-4673-8fa5-69eff5a761fd` |
128+
| `{SERVER API APP ID URI}` | Application ID URI | `api://41451fa7-82d9-4673-8fa5-69eff5a761fd` |
129+
| `{TENANT DOMAIN}` | Primary/Publisher/Tenant domain | `contoso.onmicrosoft.com` |
130+
| `{TENANT ID}` | Directory (tenant) ID | `e86c78e2-8bb4-4c41-aefd-918e0565a45e` |
131131

132132
The output location specified with the `-o|--output` option creates a project folder if it doesn't exist and becomes part of the app's name.
133133

134+
::: moniker range=">= aspnetcore-5.0"
135+
134136
> [!NOTE]
135-
> Pass the App ID URI to the `app-id-uri` option, but note a configuration change might be required in the client app, which is described in the [Access token scopes](#access-token-scopes) section.
137+
> A configuration change might be required when using an Azure tenant with an unverified publisher domain, which is described in the [App settings](#app-settings) section.
136138
137-
::: moniker range=">= aspnetcore-5.0"
139+
::: moniker-end
138140

139-
[!INCLUDE[](~/includes/blazor-security/additional-scopes-hosted-AAD.md)]
141+
::: moniker range="< aspnetcore-5.0"
142+
143+
> [!NOTE]
144+
> A configuration change might be required when using an Azure tenant with an unverified publisher domain, which is described in the [Access token scopes](#access-token-scopes) section.
140145
141146
::: moniker-end
142147

@@ -153,6 +158,24 @@ The output location specified with the `-o|--output` option creates a project fo
153158

154159
### Authentication package
155160

161+
::: moniker range=">= aspnetcore-5.0"
162+
163+
The support for authenticating and authorizing calls to ASP.NET Core Web APIs with the Microsoft Identity Platform is provided by the following packages:
164+
165+
* [`Microsoft.Identity.Web`](https://www.nuget.org/packages/Microsoft.Identity.Web)
166+
* [`Microsoft.Identity.Web.UI`](https://www.nuget.org/packages/Microsoft.Identity.Web.UI)
167+
168+
```xml
169+
<PackageReference Include="Microsoft.Identity.Web" Version="{VERSION}" />
170+
<PackageReference Include="Microsoft.Identity.Web.UI" Version="{VERSION}" />
171+
```
172+
173+
For the placeholder `{VERSION}`, the latest stable version of the package that matches the app's shared framework version can be found in the package's **Version History** at NuGet.org.
174+
175+
::: moniker-end
176+
177+
::: moniker range="< aspnetcore-5.0"
178+
156179
The support for authenticating and authorizing calls to ASP.NET Core Web APIs is provided by the [`Microsoft.AspNetCore.Authentication.AzureAD.UI`](https://www.nuget.org/packages/Microsoft.AspNetCore.Authentication.AzureAD.UI) package:
157180

158181
```xml
@@ -162,15 +185,32 @@ The support for authenticating and authorizing calls to ASP.NET Core Web APIs is
162185

163186
For the placeholder `{VERSION}`, the latest stable version of the package that matches the app's shared framework version can be found in the package's **Version History** at [NuGet.org](https://www.nuget.org/packages/Microsoft.AspNetCore.Authentication.AzureAD.UI).
164187

188+
::: moniker-end
189+
165190
### Authentication service support
166191

192+
::: moniker range=">= aspnetcore-5.0"
193+
194+
The `AddAuthentication` method sets up authentication services within the app and configures the JWT Bearer handler as the default authentication method. The <xref:Microsoft.Identity.Web.MicrosoftIdentityWebApiAuthenticationBuilderExtensions.AddMicrosoftIdentityWebApi%2A> method configures services to protect the web API with Microsoft Identity Platform v2.0. This method expects an `AzureAd` section in the app's configuration with the necessary settings to initialize authentication options.
195+
196+
```csharp
197+
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
198+
.AddMicrosoftIdentityWebApi(Configuration.GetSection("AzureAd"));
199+
```
200+
201+
::: moniker-end
202+
203+
::: moniker range="< aspnetcore-5.0"
204+
167205
The `AddAuthentication` method sets up authentication services within the app and configures the JWT Bearer handler as the default authentication method. The <xref:Microsoft.AspNetCore.Authentication.AzureADAuthenticationBuilderExtensions.AddAzureADBearer%2A> method sets up the specific parameters in the JWT Bearer handler required to validate tokens emitted by the Azure Active Directory:
168206

169207
```csharp
170208
services.AddAuthentication(AzureADDefaults.BearerAuthenticationScheme)
171209
.AddAzureADBearer(options => Configuration.Bind("AzureAd", options));
172210
```
173211

212+
::: moniker-end
213+
174214
<xref:Microsoft.AspNetCore.Builder.AuthAppBuilderExtensions.UseAuthentication%2A> and <xref:Microsoft.AspNetCore.Builder.AuthorizationAppBuilderExtensions.UseAuthorization%2A> ensure that:
175215

176216
* The app attempts to parse and validate tokens on incoming requests.
@@ -201,6 +241,40 @@ services.Configure<JwtBearerOptions>(
201241

202242
### App settings
203243

244+
::: moniker range=">= aspnetcore-5.0"
245+
246+
The `appsettings.json` file contains the options to configure the JWT bearer handler used to validate access tokens:
247+
248+
```json
249+
{
250+
"AzureAd": {
251+
"Instance": "https://login.microsoftonline.com/",
252+
"Domain": "{DOMAIN}",
253+
"TenantId": "{TENANT ID}",
254+
"ClientId": "{SERVER API APP CLIENT ID}",
255+
"CallbackPath": "/signin-oidc"
256+
}
257+
}
258+
```
259+
260+
Example:
261+
262+
```json
263+
{
264+
"AzureAd": {
265+
"Instance": "https://login.microsoftonline.com/",
266+
"Domain": "contoso.onmicrosoft.com",
267+
"TenantId": "e86c78e2-8bb4-4c41-aefd-918e0565a45e",
268+
"ClientId": "41451fa7-82d9-4673-8fa5-69eff5a761fd",
269+
"CallbackPath": "/signin-oidc"
270+
}
271+
}
272+
```
273+
274+
::: moniker-end
275+
276+
::: moniker range="< aspnetcore-5.0"
277+
204278
The `appsettings.json` file contains the options to configure the JWT bearer handler used to validate access tokens:
205279

206280
```json
@@ -227,6 +301,10 @@ Example:
227301
}
228302
```
229303

304+
::: moniker-end
305+
306+
[!INCLUDE[](~/includes/blazor-security/azure-scope-5x.md)]
307+
230308
### WeatherForecast controller
231309

232310
The WeatherForecast controller (*Controllers/WeatherForecastController.cs*) exposes a protected API with the [`[Authorize]`](xref:Microsoft.AspNetCore.Authorization.AuthorizeAttribute) attribute applied to the controller. It's **important** to understand that:
@@ -345,7 +423,7 @@ Specify additional scopes with `AdditionalScopesToConsent`:
345423
options.ProviderOptions.AdditionalScopesToConsent.Add("{ADDITIONAL SCOPE URI}");
346424
```
347425

348-
[!INCLUDE[](~/includes/blazor-security/azure-scope.md)]
426+
[!INCLUDE[](~/includes/blazor-security/azure-scope-3x.md)]
349427

350428
For more information, see the following sections of the *Additional scenarios* article:
351429

aspnetcore/blazor/security/webassembly/standalone-with-authentication-library.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ description: Learn how to secure an ASP.NET Core Blazor WebAssembly standalone a
55
monikerRange: '>= aspnetcore-3.1'
66
ms.author: riande
77
ms.custom: mvc
8-
ms.date: 07/08/2020
8+
ms.date: 10/08/2020
99
no-loc: ["ASP.NET Core Identity", cookie, Cookie, Blazor, "Blazor Server", "Blazor WebAssembly", "Identity", "Let's Encrypt", Razor, SignalR]
1010
uid: blazor/security/webassembly/standalone-with-authentication-library
1111
---
@@ -105,7 +105,7 @@ builder.Services.AddOidcAuthentication(options =>
105105
});
106106
```
107107

108-
[!INCLUDE[](~/includes/blazor-security/azure-scope.md)]
108+
[!INCLUDE[](~/includes/blazor-security/azure-scope-3x.md)]
109109

110110
For more information, see the following sections of the *Additional scenarios* article:
111111

aspnetcore/blazor/security/webassembly/standalone-with-azure-active-directory-b2c.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ description: Learn how to secure an ASP.NET Core Blazor WebAssembly standalone a
55
monikerRange: '>= aspnetcore-3.1'
66
ms.author: riande
77
ms.custom: mvc
8-
ms.date: 07/08/2020
8+
ms.date: 10/08/2020
99
no-loc: ["ASP.NET Core Identity", cookie, Cookie, Blazor, "Blazor Server", "Blazor WebAssembly", "Identity", "Let's Encrypt", Razor, SignalR]
1010
uid: blazor/security/webassembly/standalone-with-azure-active-directory-b2c
1111
---
@@ -182,7 +182,7 @@ Specify additional scopes with `AdditionalScopesToConsent`:
182182
options.ProviderOptions.AdditionalScopesToConsent.Add("{ADDITIONAL SCOPE URI}");
183183
```
184184

185-
[!INCLUDE[](~/includes/blazor-security/azure-scope.md)]
185+
[!INCLUDE[](~/includes/blazor-security/azure-scope-3x.md)]
186186

187187
For more information, see the following sections of the *Additional scenarios* article:
188188

aspnetcore/blazor/security/webassembly/standalone-with-azure-active-directory.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ description: Learn how to secure an ASP.NET Core Blazor WebAssembly standalone a
55
monikerRange: '>= aspnetcore-3.1'
66
ms.author: riande
77
ms.custom: "devx-track-csharp, mvc"
8-
ms.date: 07/08/2020
8+
ms.date: 10/08/2020
99
no-loc: ["ASP.NET Core Identity", cookie, Cookie, Blazor, "Blazor Server", "Blazor WebAssembly", "Identity", "Let's Encrypt", Razor, SignalR]
1010
uid: blazor/security/webassembly/standalone-with-azure-active-directory
1111
---
@@ -169,7 +169,7 @@ Specify additional scopes with `AdditionalScopesToConsent`:
169169
options.ProviderOptions.AdditionalScopesToConsent.Add("{ADDITIONAL SCOPE URI}");
170170
```
171171

172-
[!INCLUDE[](~/includes/blazor-security/azure-scope.md)]
172+
[!INCLUDE[](~/includes/blazor-security/azure-scope-3x.md)]
173173

174174
For more information, see the following sections of the *Additional scenarios* article:
175175

aspnetcore/blazor/security/webassembly/standalone-with-microsoft-accounts.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ description: Learn how to secure an ASP.NET Core Blazor WebAssembly standalone a
55
monikerRange: '>= aspnetcore-3.1'
66
ms.author: riande
77
ms.custom: mvc
8-
ms.date: 07/08/2020
8+
ms.date: 10/08/2020
99
no-loc: ["ASP.NET Core Identity", cookie, Cookie, Blazor, "Blazor Server", "Blazor WebAssembly", "Identity", "Let's Encrypt", Razor, SignalR]
1010
uid: blazor/security/webassembly/standalone-with-microsoft-accounts
1111
---
@@ -162,7 +162,7 @@ Specify additional scopes with `AdditionalScopesToConsent`:
162162
options.ProviderOptions.AdditionalScopesToConsent.Add("{ADDITIONAL SCOPE URI}");
163163
```
164164

165-
[!INCLUDE[](~/includes/blazor-security/azure-scope.md)]
165+
[!INCLUDE[](~/includes/blazor-security/azure-scope-3x.md)]
166166

167167
For more information, see the following sections of the *Additional scenarios* article:
168168

aspnetcore/includes/blazor-security/additional-scopes-hosted-AAD.md

Lines changed: 0 additions & 9 deletions
This file was deleted.

aspnetcore/includes/blazor-security/additional-scopes-hosted-nonAAD.md

Lines changed: 0 additions & 10 deletions
This file was deleted.
Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1-
Add a pair of <xref:Microsoft.Authentication.WebAssembly.Msal.Models.MsalProviderOptions> for `User.Read` <xref:Microsoft.Authentication.WebAssembly.Msal.Models.MsalProviderOptions.DefaultAccessTokenScopes>:
1+
Add a <xref:Microsoft.Authentication.WebAssembly.Msal.Models.MsalProviderOptions> for `User.Read` permission with <xref:Microsoft.Authentication.WebAssembly.Msal.Models.MsalProviderOptions.DefaultAccessTokenScopes>:
22

33
```csharp
44
builder.Services.AddMsalAuthentication(options =>
55
{
66
...
7-
options.ProviderOptions.DefaultAccessTokenScopes.Add("User.Read");
7+
options.ProviderOptions.DefaultAccessTokenScopes
8+
.Add("https://graph.microsoft.com/User.Read");
89
});
910
```

0 commit comments

Comments
 (0)