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
<xref:Microsoft.AspNetCore.Http.IHttpContextAccessor> generally should be avoided with interactive rendering because a valid <xref:Microsoft.AspNetCore.Http.HttpContext> isn't always available.
18
18
19
-
<xref:Microsoft.AspNetCore.Http.IHttpContextAccessor> can be used for components that are statically rendered on the server. **However, we recommend avoiding it if possible.**
19
+
<xref:Microsoft.AspNetCore.Http.IHttpContextAccessor> can be used for components that are statically rendered on the server. **However, we recommend avoiding it if possible.** Another valid use case for static server-side rendering is [passing tokens to a server-side app](xref:blazor/security/additional-scenarios#pass-tokens-to-a-server-side-blazor-app).
20
20
21
21
<xref:Microsoft.AspNetCore.Http.HttpContext> can be used as a [cascading parameter](xref:Microsoft.AspNetCore.Components.CascadingParameterAttribute) only in *statically-rendered root components* for general tasks, such as inspecting and modifying headers or other properties in the `App` component (`Components/App.razor`). The value is always `null` for interactive rendering.
22
22
@@ -32,7 +32,7 @@ For additional context in *advanced* edge cases†, see the discussion in t
32
32
*[HttpContext is valid in Interactive Server Rendering Blazor page (`dotnet/AspNetCore.Docs`#34301)](https://github.com/dotnet/AspNetCore.Docs/issues/34301)
33
33
*[Security implications of using IHttpContextAccessor in Blazor Server (`dotnet/aspnetcore`#45699)](https://github.com/dotnet/aspnetcore/issues/45699)
34
34
35
-
†Most developers building and maintaining Blazor apps don't need to delve into advanced concepts as long as the general guidance in this article is followed.
35
+
†Most developers building and maintaining Blazor apps don't need to delve into advanced concepts when the general guidance in this article is followed.
@@ -270,12 +270,16 @@ The following specification is covered:
270
270
* The Blazor Web App uses [the Server render mode with global interactivity](xref:blazor/components/render-modes).
271
271
* This app is a starting point for any OIDC authentication flow. OIDC is configured manually in the app and doesn't rely upon [Microsoft Entra ID](https://www.microsoft.com/security/business/microsoft-entra) or [Microsoft Identity Web](/entra/msal/dotnet/microsoft-identity-web/) packages, nor does the sample app require [Microsoft Azure](https://azure.microsoft.com/) hosting. However, the sample app can be used with Entra, Microsoft Identity Web, and hosted in Azure.
272
272
* Automatic non-interactive token refresh.
273
+
* A separate web API project demonstrates a secure web API call for weather data.
273
274
274
275
For an alternative experience using [Microsoft Authentication Library for .NET](/entra/msal/dotnet/), [Microsoft Identity Web](/entra/msal/dotnet/microsoft-identity-web/), and [Microsoft Entra ID](https://www.microsoft.com/security/business/identity-access/microsoft-entra-id), see <xref:blazor/security/blazor-web-app-entra>.
275
276
276
277
## Sample app
277
278
278
-
The sample app consists of a single server-side Blazor Web App project (`BlazorWebAppOidcServer`).
279
+
The sample app consists of the following projects:
280
+
281
+
*`BlazorWebAppOidc`: Blazor Web App server-side project (global Interactive Server rendering).
282
+
*`MinimalApiJwt`: Backend web API with a [Minimal API](xref:fundamentals/minimal-apis) endpoint for weather data.
279
283
280
284
Access the sample through the latest version folder in the Blazor samples repository with the following link. The sample is in the `BlazorWebAppOidcServer` folder for .NET 8 or later.
281
285
@@ -311,7 +315,7 @@ dotnet user-secrets set "Authentication:Schemes:MicrosoftOidc:ClientSecret" "{SE
311
315
312
316
If using Visual Studio, you can confirm the secret is set by right-clicking the project in **Solution Explorer** and selecting **Manage User Secrets**.
313
317
314
-
### Configure the app
318
+
### Configure the `BlazorWebAppOidcServer` project
315
319
316
320
The following <xref:Microsoft.AspNetCore.Authentication.OpenIdConnect.OpenIdConnectOptions> configuration is found in the project's `Program` file on the call to <xref:Microsoft.Extensions.DependencyInjection.OpenIdConnectExtensions.AddOpenIdConnect%2A>:
317
321
@@ -337,6 +341,35 @@ The following <xref:Microsoft.AspNetCore.Authentication.OpenIdConnect.OpenIdConn
* Configure the `Weather.Get` scope for accessing the external web API for weather data. The following example is based on using Entra ID in an ME-ID tenant domain. In the following example, the `{APP ID URI}` placeholder is found in the Entra or Azure portal where the web API is exposed. For any other identity provider, use the appropriate scope.
345
+
346
+
```csharp
347
+
oidcOptions.Scope.Add("{APP ID URI}/Weather.Get");
348
+
```
349
+
350
+
Placeholders in the following examples:
351
+
352
+
* Directory Name (`{DIRECTORY NAME}`): `contoso`
353
+
* Application (Client) Id (`{CLIENT ID}`): `00001111-aaaa-2222-bbbb-3333cccc4444`
354
+
355
+
The format of the scope depends on the type of tenant in use:
356
+
357
+
* ME-ID tenant App ID URI (`{APP ID URI}`): `api://{CLIENT ID}`
Inspect the sample app for the following features:
483
+
Configure the project in the <xref:Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerOptions> of the <xref:Microsoft.Extensions.DependencyInjection.JwtBearerExtensions.AddJwtBearer%2A> call in the project's `Program` file.
451
484
452
-
* Automatic non-interactive token refresh with the help of a custom cookie refresher (`CookieOidcRefresher.cs`).
453
-
* The `Weather` component uses the [`[Authorize]` attribute](xref:Microsoft.AspNetCore.Authorization.AuthorizeAttribute) to prevent unauthorized access. For more information on requiring authorization across the app via an [authorization policy](xref:security/authorization/policies) and opting out of authorization at a subset of public endpoints, see the [Razor Pages OIDC guidance](xref:security/authentication/configure-oidc-web-authentication#force-authorization). For more information on how this app secures weather data, see [Secure data in Blazor Web Apps with Interactive Auto rendering](xref:blazor/security/index#secure-data-in-blazor-web-apps-with-interactive-auto-rendering).
485
+
The <xref:Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerOptions.Authority%2A> sets the Authority for making OIDC calls. We recommend using a separate app registration for the `MinimalApiJwt` project. The authority matches the issurer (`iss`) of the JWT returned by the identity provider.
486
+
487
+
```csharp
488
+
jwtOptions.Authority="{AUTHORITY}";
489
+
```
490
+
491
+
The format of the Authority depends on the type of tenant in use. The following examples for Microsoft Entra ID use a Tenant ID of `aaaabbbb-0000-cccc-1111-dddd2222eeee`:
The <xref:Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerOptions.Audience%2A> sets the Audience for any received OIDC token.
506
+
507
+
```csharp
508
+
jwtOptions.Audience="{APP ID URI}";
509
+
```
510
+
511
+
> [!NOTE]
512
+
> When using Microsoft Entra ID, match the value to just the path of the **Application ID URI** configured when adding the `Weather.Get` scope under **Expose an API** in the Entra or Azure portal.
513
+
514
+
The format of the Audience depends on the type of tenant in use. The following examples for Microsoft Entra ID use a Client ID (`{CLIENT ID}`) of `00001111-aaaa-2222-bbbb-3333cccc4444`:
515
+
516
+
* ME-ID tenant App ID URI (`{APP ID URI}`): `api://{CLIENT ID}`.
* AAD B2C tenant App ID URI (`{APP ID URI}`): `https://{DIRECTORY NAME}.onmicrosoft.com/{CLIENT ID}`. The following example uses a directory name (`{DIRECTORY NAME}`) of `contoso`.
The `MinimalApiJwt.http` file can be used for testing the weather data request. Note that the `MinimalApiJwt` project must be running to test the endpoint, and the endpoint is hardcoded into the file. For more information, see <xref:test/http-files>.
552
+
553
+
### `BlazorWebAppOidc` project
554
+
555
+
Automatic non-interactive token refresh is managed by a custom cookie refresher (`CookieOidcRefresher.cs`).
556
+
557
+
A <xref:System.Net.Http.DelegatingHandler> (`TokenHandler`) manages attaching a user's access token to outgoing requests. The token handler only executes during static server-side rendering (static SSR), so using <xref:Microsoft.AspNetCore.Http.HttpContext> is safe in this scenario. For more information, see <xref:blazor/components/httpcontext> and <xref:blazor/security/additional-scenarios#pass-tokens-to-a-server-side-blazor-app>.
In the project's `Program` file, the token handler (`TokenHandler`) is registered as a service and specified as the message handler with <xref:Microsoft.Extensions.DependencyInjection.HttpClientBuilderExtensions.AddHttpMessageHandler%2A> for making secure requests to the backend `MinimalApiJwt` web API using a [named HTTP client](xref:blazor/call-web-api#named-httpclient-with-ihttpclientfactory) ("`ExternalApi`").
The `Weather` component uses the [`[Authorize]` attribute](xref:Microsoft.AspNetCore.Authorization.AuthorizeAttribute) to prevent unauthorized access. For more information on requiring authorization across the app via an [authorization policy](xref:security/authorization/policies) and opting out of authorization at a subset of public endpoints, see the [Razor Pages OIDC guidance](xref:security/authentication/configure-oidc-web-authentication#force-authorization).
592
+
593
+
The `ExternalApi` HTTP client is used to make a request for weather data to the secure web API. In the [`OnInitializedAsync` lifecycle event](xref:blazor/components/lifecycle#component-initialization-oninitializedasync) of `Weather.razor`:
@@ -754,56 +906,49 @@ The `MinimalApiJwt.http` file can be used for testing the weather data request.
754
906
755
907
### Configuration
756
908
757
-
Configure the project in the <xref:Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerOptions> of the <xref:Microsoft.Extensions.DependencyInjection.JwtBearerExtensions.AddJwtBearer%2A> call in the project's `Program` file:
909
+
Configure the project in the <xref:Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerOptions> of the <xref:Microsoft.Extensions.DependencyInjection.JwtBearerExtensions.AddJwtBearer%2A> call in the project's `Program` file.
758
910
759
-
*<xref:Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerOptions.Audience%2A>: Sets the Audience for any received OIDC token.
911
+
The<xref:Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerOptions.Authority%2A> sets the Authority for making OIDC calls. We recommend using a separate app registration for the `MinimalApiJwt` project. The authority matches the issurer (`iss`) of the JWT returned by the identity provider.
760
912
761
-
```csharp
762
-
jwtOptions.Audience="{APP ID URI}";
763
-
```
764
-
765
-
> [!NOTE]
766
-
> When using Microsoft Entra ID, match the value to just the path of the **Application ID URI** configured when adding the `Weather.Get` scope under **Expose an API** in the Entra or Azure portal.
913
+
```csharp
914
+
jwtOptions.Authority="{AUTHORITY}";
915
+
```
767
916
768
-
Example:
917
+
The format of the Authority depends on the type of tenant in use. The following examples for Microsoft Entra ID use a Tenant ID of `aaaabbbb-0000-cccc-1111-dddd2222eeee`:
769
918
770
-
App ID URI (`{APP ID URI}`): `https://{DIRECTORY NAME}.onmicrosoft.com/{CLIENT ID}`:
771
-
772
-
* Directory Name (`{DIRECTORY NAME}`): `contoso`
773
-
* Application (Client) Id (`{CLIENT ID}`): `00001111-aaaa-2222-bbbb-3333cccc4444`
The preceding example pertains to an app registered in a tenant with an AAD B2C tenant type. If the app is registered in an ME-ID tenant, the App ID URI is different, thus the audience is different.
780
-
781
-
Example:
782
-
783
-
App ID URI (`{APP ID URI}`): `api://{CLIENT ID}` with Application (Client) Id (`{CLIENT ID}`): `00001111-aaaa-2222-bbbb-3333cccc4444`
*<xref:Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerOptions.Authority%2A>: Sets the Authority for making OIDC calls. Match the value to the Authority configured for the OIDC handler in `BlazorWebAppOidc/Program.cs`:
931
+
The<xref:Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerOptions.Audience%2A> sets the Audience for any received OIDC token.
790
932
791
-
```csharp
792
-
jwtOptions.Authority="{AUTHORITY}";
793
-
```
933
+
```csharp
934
+
jwtOptions.Audience="{APP ID URI}";
935
+
```
794
936
795
-
Example:
937
+
> [!NOTE]
938
+
> When using Microsoft Entra ID, match the value to just the path of the **Application ID URI** configured when adding the `Weather.Get` scope under **Expose an API** in the Entra or Azure portal.
939
+
940
+
The format of the Audience depends on the type of tenant in use. The following examples use a Client ID (`{CLIENT ID}`) of `00001111-aaaa-2222-bbbb-3333cccc4444`:
796
941
797
-
Authority (`{AUTHORITY}`): `https://login.microsoftonline.com/aaaabbbb-0000-cccc-1111-dddd2222eeee/v2.0/` (uses Tenant ID `aaaabbbb-0000-cccc-1111-dddd2222eeee`)
942
+
* ME-ID tenant App ID URI (`{APP ID URI}`): `api://{CLIENT ID}`.
The preceding example pertains to an app registered in a tenant with an AAD B2C tenant type. If the app is registered in an ME-ID tenant, the authority should match the issurer (`iss`) of the JWT returned by the identity provider:
948
+
*AAD B2C tenant App ID URI (`{APP ID URI}`): `https://{DIRECTORY NAME}.onmicrosoft.com/{CLIENT ID}`. The following example uses a directory name (`{DIRECTORY NAME}`) of `contoso`.
@@ -829,6 +974,18 @@ The <xref:Microsoft.AspNetCore.Builder.AuthorizationEndpointConventionBuilderExt
829
974
830
975
:::zone-end
831
976
977
+
## Microsoft Entra ID app registrations
978
+
979
+
We recommend using separate registrations for apps and web APIs, even when the apps and web APIs are in the same solution.
980
+
981
+
When using Microsoft Entra ID, grant API permission to the app (`BlazorWebAppOidcServer`) to access the web API (`MinimalApiJwt`):
982
+
983
+
* The web API's (`MinimalApiJwt`) registration exposes its API in **App registrations** > **Expose an API**.
984
+
985
+
* The app (`BlazorWebAppOidcServer`) registration grants users delegated access to the web API in **App registrations** > **API permissions**. Grant admin consent for the organization to access the web API.
986
+
987
+
* Authorized users and groups are assigned to the app's (`BlazorWebAppOidcServer`) registration in **Enterprise applications**.
988
+
832
989
## Redirect to the home page on logout
833
990
834
991
The `LogInOrOut` component (`Layout/LogInOrOut.razor`) sets a hidden field for the return URL (`ReturnUrl`) to the current URL (`currentURL`). When the user signs out of the app, the identity provider returns the user to the page from which they logged out. If the user logs out from a secure page, they're returned to the same secure page and sent back through the authentication process. This authentication flow is reasonable when users need to change accounts regularly.
0 commit comments