From 57ab8dfc6a8bd19be99e0e08d0004b0f512a648b Mon Sep 17 00:00:00 2001 From: guardrex <1622880+guardrex@users.noreply.github.com> Date: Wed, 9 Oct 2024 11:53:56 -0400 Subject: [PATCH] Update BWA+OIDC article for 9.0 --- .../security/blazor-web-app-with-oidc.md | 94 ++++++++++++++----- 1 file changed, 71 insertions(+), 23 deletions(-) diff --git a/aspnetcore/blazor/security/blazor-web-app-with-oidc.md b/aspnetcore/blazor/security/blazor-web-app-with-oidc.md index 77553c551848..15f619f445a2 100644 --- a/aspnetcore/blazor/security/blazor-web-app-with-oidc.md +++ b/aspnetcore/blazor/security/blazor-web-app-with-oidc.md @@ -5,7 +5,7 @@ description: Learn how to secure a Blazor WebAssembly App with OpenID Connect (O monikerRange: '>= aspnetcore-8.0' ms.author: riande ms.custom: mvc -ms.date: 05/28/2024 +ms.date: 10/09/2024 uid: blazor/security/blazor-web-app-oidc zone_pivot_groups: blazor-web-app-oidc-specification --- @@ -56,7 +56,26 @@ The `BlazorWebAppOidc.http` file can be used for testing the weather data reques This section explains how to configure the sample app. > [!NOTE] -> For Microsoft Entra ID and Azure AD B2C, you can use from [Microsoft Identity Web](/entra/msal/dotnet/microsoft-identity-web/) ([`Microsoft.Identity.Web` NuGet package](https://www.nuget.org/packages/Microsoft.Identity.Web), [API documentation]()), which adds both the OIDC and Cookie authentication handlers with the appropriate defaults. The sample app and the guidance in this section doesn't use Microsoft Identity Web. The guidance demonstrates how to configure the OIDC handler *manually* for any OIDC provider. For more information on implementing Microsoft Identity Web, see the linked resources. +> For Microsoft Entra ID or Azure AD B2C, you can use from [Microsoft Identity Web](/entra/msal/dotnet/microsoft-identity-web/) ([`Microsoft.Identity.Web` NuGet package](https://www.nuget.org/packages/Microsoft.Identity.Web), [API documentation]()), which adds both the OIDC and Cookie authentication handlers with the appropriate defaults. The sample app and the guidance in this section doesn't use Microsoft Identity Web. The guidance demonstrates how to configure the OIDC handler *manually* for any OIDC provider. For more information on implementing Microsoft Identity Web, see the linked resources. + +#### Establish the client secret + +[!INCLUDE[](~/blazor/security/includes/secure-authentication-flows.md)] + +For local development testing, use the [Secret Manager tool](xref:security/app-secrets) to store the server app's client secret under the configuration key `MicrosoftOidc:ClientSecret`. + +> [!NOTE] +> If the app uses Microsoft Entra ID or Azure AD B2C, create a client secret in the app's registration in the Entra or Azure portal (**Manage** > **Certificates & secrets** > **New client secret**). Use the **Value** of the new secret in the following guidance. + +Execute the following command in a command shell from the server project's directory, such as the Developer PowerShell command shell in Visual Studio. The `{SECRET}` placeholder is the client secret obtained from the app's registration: + +```dotnetcli +dotnet user-secrets set "MicrosoftOidc:ClientSecret" "{SECRET}" +``` + +If using Visual Studio, you can confirm the secret is set by right-clicking the server project in **Solution Explorer** and selecting **Manage User Secrets**. + +#### Configure the app The following configuration is found in the project's `Program` file on the call to : @@ -109,15 +128,6 @@ The following : The OIDC client secret. - - Don't store the client secret in the app's assembly or check the secret into source control. For more information, see [Securely maintain sensitive data and credentials](xref:blazor/security/index#securely-maintain-sensitive-data-and-credentials). - - **For local development and testing**, use one of the following approaches: - - * Use the [Secret Manager tool](xref:security/app-secrets) to secure the secret locally. - * Authentication scheme configuration is automatically read from `builder.Configuration["Authentication:Schemes:{SCHEME NAME}:{PropertyName}"]`, where the `{SCHEME NAME}` placeholder is the scheme, which is `MicrosoftOidc`. The client secret can automatically be read during local development via the `Authentication:Schemes:MicrosoftOidc:ClientSecret` configuration key from an `appsettings.Development.json` file. - * : Configures the OIDC handler to only perform authorization code flow. Implicit grants and hybrid flows are unnecessary in this mode. In the Entra or Azure portal's **Implicit grant and hybrid flows** app registration configuration, do **not** select either checkbox for the authorization endpoint to return **Access tokens** or **ID tokens**. The OIDC handler automatically requests the appropriate tokens using the code returned from the authorization endpoint. @@ -196,6 +206,19 @@ The following to flow the authentication state to the client. The client calls `AddAuthenticationStateDeserialization` to deserialize and use the authentication state passed by the server. The authentication state is fixed for the lifetime of the WebAssembly application. +* An example requests to the Blazor Web App for weather data is handled by a Minimal API endpoint (`/weather-forecast`) in the `Program` file (`Program.cs`). The endpoint requires authorization by calling . For any controllers that you add to the project, add the [`[Authorize]` attribute](xref:Microsoft.AspNetCore.Authorization.AuthorizeAttribute) to the controller or action. +* The app securely calls a (web) API in the server project for weather data: + * When rendering the `Weather` component on the server, the component uses the `ServerWeatherForecaster` on the server to obtain weather data directly (not via a web API call). + * When the component is rendered on the client, the component uses the `ClientWeatherForecaster` service implementation, which uses a preconfigured (in the client project's `Program` file) to make a web API call to the server project. A Minimal API endpoint (`/weather-forecast`) defined in the server project's `Program` file obtains the weather data from the `ServerWeatherForecaster` and returns the data to the client. + +:::moniker-end + +:::moniker range="< aspnetcore-9.0" + * Automatic non-interactive token refresh with the help of a custom cookie refresher (`CookieOidcRefresher.cs`). * The `PersistingAuthenticationStateProvider` class (`PersistingAuthenticationStateProvider.cs`) is a server-side that uses to flow the authentication state to the client, which is then fixed for the lifetime of the WebAssembly application. * An example requests to the Blazor Web App for weather data is handled by a Minimal API endpoint (`/weather-forecast`) in the `Program` file (`Program.cs`). The endpoint requires authorization by calling . For any controllers that you add to the project, add the [`[Authorize]` attribute](xref:Microsoft.AspNetCore.Authorization.AuthorizeAttribute) to the controller or action. @@ -203,6 +226,8 @@ Inspect the sample app for the following features: * When rendering the `Weather` component on the server, the component uses the `ServerWeatherForecaster` on the server to obtain weather data directly (not via a web API call). * When the component is rendered on the client, the component uses the `ClientWeatherForecaster` service implementation, which uses a preconfigured (in the client project's `Program` file) to make a web API call to the server project. A Minimal API endpoint (`/weather-forecast`) defined in the server project's `Program` file obtains the weather data from the `ServerWeatherForecaster` and returns the data to the client. +:::moniker-end + For more information on (web) API calls using a service abstractions in Blazor Web Apps, see . ## Client-side Blazor Web App project (`BlazorWebAppOidc.Client`) @@ -277,7 +302,26 @@ The `BlazorWebAppOidc.http` file can be used for testing the weather data reques This section explains how to configure the sample app. > [!NOTE] -> For Microsoft Entra ID and Azure AD B2C, you can use from [Microsoft Identity Web](/entra/msal/dotnet/microsoft-identity-web/) ([`Microsoft.Identity.Web` NuGet package](https://www.nuget.org/packages/Microsoft.Identity.Web), [API documentation]()), which adds both the OIDC and Cookie authentication handlers with the appropriate defaults. The sample app and the guidance in this section doesn't use Microsoft Identity Web. The guidance demonstrates how to configure the OIDC handler *manually* for any OIDC provider. For more information on implementing Microsoft Identity Web, see the linked resources. +> For Microsoft Entra ID or Azure AD B2C, you can use from [Microsoft Identity Web](/entra/msal/dotnet/microsoft-identity-web/) ([`Microsoft.Identity.Web` NuGet package](https://www.nuget.org/packages/Microsoft.Identity.Web), [API documentation]()), which adds both the OIDC and Cookie authentication handlers with the appropriate defaults. The sample app and the guidance in this section doesn't use Microsoft Identity Web. The guidance demonstrates how to configure the OIDC handler *manually* for any OIDC provider. For more information on implementing Microsoft Identity Web, see the linked resources. + +#### Establish the client secret + +[!INCLUDE[](~/blazor/security/includes/secure-authentication-flows.md)] + +For local development testing, use the [Secret Manager tool](xref:security/app-secrets) to store the server app's client secret under the configuration key `MicrosoftOidc:ClientSecret`. + +> [!NOTE] +> If the app uses Microsoft Entra ID or Azure AD B2C, create a client secret in the app's registration in the Entra or Azure portal (**Manage** > **Certificates & secrets** > **New client secret**). Use the **Value** of the new secret in the following guidance. + +Execute the following command in a command shell from the server project's directory, such as the Developer PowerShell command shell in Visual Studio. The `{SECRET}` placeholder is the client secret obtained from the app's registration: + +```dotnetcli +dotnet user-secrets set "MicrosoftOidc:ClientSecret" "{SECRET}" +``` + +If using Visual Studio, you can confirm the secret is set by right-clicking the server project in **Solution Explorer** and selecting **Manage User Secrets**. + +#### Configure the app The following configuration is found in the project's `Program` file on the call to : @@ -358,15 +402,6 @@ The following : The OIDC client secret. - - Don't store the client secret in the app's assembly or check the secret into source control. For more information, see [Securely maintain sensitive data and credentials](xref:blazor/security/index#securely-maintain-sensitive-data-and-credentials). - - **For local development and testing**, use one of the following approaches: - - * Use the [Secret Manager tool](xref:security/app-secrets) to secure the secret locally. - * Authentication scheme configuration is automatically read from `builder.Configuration["Authentication:Schemes:{SCHEME NAME}:{PropertyName}"]`, where the `{SCHEME NAME}` placeholder is the scheme, which is `MicrosoftOidc`. The client secret can automatically be read during local development via the `Authentication:Schemes:MicrosoftOidc:ClientSecret` configuration key from an `appsettings.Development.json` file. - * : Configures the OIDC handler to only perform authorization code flow. Implicit grants and hybrid flows are unnecessary in this mode. In the Entra or Azure portal's **Implicit grant and hybrid flows** app registration configuration, do **not** select either checkbox for the authorization endpoint to return **Access tokens** or **ID tokens**. The OIDC handler automatically requests the appropriate tokens using the code returned from the authorization endpoint. @@ -445,12 +480,26 @@ The following to flow the authentication state to the client. The client calls `AddAuthenticationStateDeserialization` to deserialize and use the authentication state passed by the server. The authentication state is fixed for the lifetime of the WebAssembly application. +* Requests to the Blazor Web App are proxied to the backend web API project (`MinimalApiJwt`). `MapForwarder` in the `Program` file adds direct forwarding of HTTP requests that match the specified pattern to a specific destination using default configuration for the outgoing request, customized transforms, and default HTTP client: + * When rendering the `Weather` component on the server, the component uses the `ServerWeatherForecaster` to proxy the request for weather data with the user's access token. + * When the component is rendered on the client, the component uses the `ClientWeatherForecaster` service implementation, which uses a preconfigured (in the client project's `Program` file) to make a web API call to the server project. A Minimal API endpoint (`/weather-forecast`) defined in the server project's `Program` file transforms the request with the user's access token to obtain the weather data. + +:::moniker-end + +:::moniker range="< aspnetcore-9.0" + * Automatic non-interactive token refresh with the help of a custom cookie refresher (`CookieOidcRefresher.cs`). * The `PersistingAuthenticationStateProvider` class (`PersistingAuthenticationStateProvider.cs`) is a server-side that uses to flow the authentication state to the client, which is then fixed for the lifetime of the WebAssembly application. * Requests to the Blazor Web App are proxied to the backend web API project (`MinimalApiJwt`). `MapForwarder` in the `Program` file adds direct forwarding of HTTP requests that match the specified pattern to a specific destination using default configuration for the outgoing request, customized transforms, and default HTTP client: * When rendering the `Weather` component on the server, the component uses the `ServerWeatherForecaster` to proxy the request for weather data with the user's access token. * When the component is rendered on the client, the component uses the `ClientWeatherForecaster` service implementation, which uses a preconfigured (in the client project's `Program` file) to make a web API call to the server project. A Minimal API endpoint (`/weather-forecast`) defined in the server project's `Program` file transforms the request with the user's access token to obtain the weather data. +:::moniker-end + For more information on (web) API calls using a service abstractions in Blazor Web Apps, see . ## Client-side Blazor Web App project (`BlazorWebAppOidc.Client`) @@ -559,7 +608,7 @@ When a user navigates around the app, the `LogInOrOut` component (`Layout/LogInO If the user signs out from a secure page, they're returned back to the same secure page after signing out only to be sent back through the authentication process. This behavior is fine when users need to switch accounts frequently. However, a alternative app specification may call for the user to be returned to the app's home page or some other page after signout. The following example shows how to set the app's home page as the return URL for signout operations. -The important changes to the `LogInOrOut` component are demonstrated in the following example. The `value` of the hidden field for the `ReturnUrl` is set to the home page at `/`. is no longer implemented. The is no longer injected. The entire `@code` block is removed. +The important changes to the `LogInOrOut` component are demonstrated in the following example. There's no need to provide a hidden field for the `ReturnUrl` set to the home page at `/` because that's the default path. is no longer implemented. The is no longer injected. The entire `@code` block is removed. `Layout/LogInOrOut.razor`: @@ -571,7 +620,6 @@ The important changes to the `LogInOrOut` component are demonstrated in the foll
-