diff --git a/aspnetcore/blazor/call-web-api.md b/aspnetcore/blazor/call-web-api.md index 3215eb6ee17e..f3b68531f510 100644 --- a/aspnetcore/blazor/call-web-api.md +++ b/aspnetcore/blazor/call-web-api.md @@ -231,8 +231,8 @@ For more information, see the following resources: * [A web API that calls web APIs: Call an API: Option 2: Call a downstream web API with the helper class](/entra/identity-platform/scenario-web-api-call-api-call-api?tabs=aspnetcore#option-2-call-a-downstream-web-api-with-the-helper-class) * * *Secure an ASP.NET Core Blazor Web App with Microsoft Entra ID* - * [Non-BFF pattern (Interactive Auto)](xref:blazor/security/blazor-web-app-entra?pivots=non-bff-pattern) - * [BFF pattern (Interactive Auto)](xref:blazor/security/blazor-web-app-entra?pivots=non-bff-pattern-server) + * [With YARP and Aspire (Interactive Auto)](xref:blazor/security/blazor-web-app-entra?pivots=with-yarp-and-aspire) + * [Without YARP and Aspire (Interactive Auto)](xref:blazor/security/blazor-web-app-entra?pivots=without-yarp-and-aspire) * [Host ASP.NET Core in a web farm: Data Protection](xref:host-and-deploy/web-farm#data-protection) * [Azure Key Vault documentation](/azure/key-vault/general/) * [Azure Storage documentation](/azure/storage/) diff --git a/aspnetcore/blazor/security/additional-scenarios.md b/aspnetcore/blazor/security/additional-scenarios.md index 23740c25252e..f86c03279355 100644 --- a/aspnetcore/blazor/security/additional-scenarios.md +++ b/aspnetcore/blazor/security/additional-scenarios.md @@ -99,7 +99,7 @@ builder.Services.AddHttpClient("ExternalApi", > [!CAUTION] > Ensure that tokens are never transmitted and handled by the client (the `.Client` project), for example, in a component that adopts Interactive Auto rendering and is rendered on the client or by a client-side service. Always have the client call the server (project) to process requests with tokens. **Tokens and other authentication data should never leave the server.** > -> For Interactive Auto components, see , which demonstrates how to leave access tokens and other authentication properties on the server. Also, consider adopting the Backend-for-Frontend (BFF) pattern, which adopts a similar call structure and is described in for OIDC providers and for Microsoft Identity Web with Entra. +> For Interactive Auto components, see , which demonstrates how to leave access tokens and other authentication properties on the server. Also, consider adopting the Backend-for-Frontend (BFF) pattern, which adopts a similar call structure and is described in for OIDC providers and for Microsoft Identity Web with Entra. ## Use a token handler for web API calls diff --git a/aspnetcore/blazor/security/blazor-web-app-with-entra.md b/aspnetcore/blazor/security/blazor-web-app-with-entra.md index c97d98b9622a..37070fe6bab7 100644 --- a/aspnetcore/blazor/security/blazor-web-app-with-entra.md +++ b/aspnetcore/blazor/security/blazor-web-app-with-entra.md @@ -5,7 +5,7 @@ description: Learn how to secure a Blazor Web App with Microsoft Entra ID. monikerRange: '>= aspnetcore-9.0' ms.author: wpickett ms.custom: mvc, sfi-ropc-nochange -ms.date: 11/11/2025 +ms.date: 12/17/2025 uid: blazor/security/blazor-web-app-entra zone_pivot_groups: blazor-web-app-entra-specification --- @@ -14,13 +14,14 @@ zone_pivot_groups: blazor-web-app-entra-specification This article describes how to secure a Blazor Web App with [Microsoft identity platform](/entra/identity-platform/) with [Microsoft Identity Web packages](/entra/msal/dotnet/microsoft-identity-web/) for [Microsoft Entra ID](https://www.microsoft.com/security/business/microsoft-entra) using a sample app. -:::zone pivot="non-bff-pattern" +:::zone pivot="with-yarp-and-aspire" -This version of the article covers implementing Entra without adopting the [Backend for Frontend (BFF) pattern](/azure/architecture/patterns/backends-for-frontends). The BFF pattern is useful for making authenticated requests to external services. Change the article version selector to **BFF pattern** if the app's specification calls for adopting the BFF pattern. +This version of the article covers implementing Entra with the [Backend for Frontend (BFF) pattern](/azure/architecture/patterns/backends-for-frontends) with [YARP](https://dotnet.github.io/yarp/) and [Aspire](/dotnet/aspire/get-started/aspire-overview). Change the article version selector to **Without YARP and Aspire** if the app's specification doesn't call for adopting YARP and Aspire. The following specification is covered: @@ -28,19 +29,32 @@ The following specification is covered: * The server project calls to add a server-side authentication state provider that uses to flow the authentication state to the client. The client calls to deserialize and use the authentication state passed by the server. The authentication state is fixed for the lifetime of the WebAssembly application. * The app uses [Microsoft Entra ID](https://www.microsoft.com/security/business/microsoft-entra), based on [Microsoft Identity Web](/entra/msal/dotnet/microsoft-identity-web/) packages. * Automatic non-interactive token refresh is managed by the framework. -* The app uses server-side and client-side service abstractions to display generated weather data: +* The [Backend for Frontend (BFF) pattern](/azure/architecture/patterns/backends-for-frontends) is adopted using [Aspire](/dotnet/aspire/get-started/aspire-overview) for service discovery and [YARP](https://dotnet.github.io/yarp/) for proxying requests to a weather forecast endpoint on the backend app. + * A backend web API uses JWT-bearer authentication to validate JWT tokens saved by the Blazor Web App in the sign-in cookie. + * Aspire improves the experience of building .NET cloud-native apps. It provides a consistent, opinionated set of tools and patterns for building and running distributed apps. + * YARP (Yet Another Reverse Proxy) is a library used to create a reverse proxy server. +* The app uses server-side and client-side service abstractions to display generated weather data. * When rendering the `Weather` component on the server to display weather data, the component uses the `ServerWeatherForecaster`. Microsoft Identity Web packages provide API to create a named downstream web service for making web API calls. is injected into the `ServerWeatherForecaster`, which is used to call to obtain weather data from an external web API (`MinimalApiJwt` project). - * When the `Weather` 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's Minimal API (`/weather-forecast`) for weather data. The Minimal API endpoint obtains the weather data from the `ServerWeatherForecaster` class and returns it to the client for rendering by the component. + * When the `Weather` 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's Minimal API (`/weather-forecast`) for weather data. The Minimal API endpoint obtains an access token for the user by calling . Along with the correct scopes, a reverse proxy call is made to the external web API (`MinimalApiJwt` project) to obtain and return weather data to the client for rendering by the component. + +## Prerequisites + +[Aspire](/dotnet/aspire/get-started/aspire-overview) requires [Visual Studio](https://visualstudio.microsoft.com/) version 17.10 or later. + +Also, see the *Prerequisites* section of [Quickstart: Build your first Aspire solution](/dotnet/aspire/get-started/build-your-first-aspire-app?tabs=visual-studio#prerequisites). ## Sample solution The sample solution consists of the following projects: -* `BlazorWebAppEntra`: Server-side project of the Blazor Web App, containing an example [Minimal API](xref:fundamentals/minimal-apis) endpoint for weather data. -* `BlazorWebAppEntra.Client`: Client-side project of the Blazor Web App. +* Aspire: + * `Aspire.AppHost`: Used to manage the high-level orchestration concerns of the app. + * `Aspire.ServiceDefaults`: Contains default Aspire app configurations that can be extended and customized as needed. * `MinimalApiJwt`: Backend web API, containing an example [Minimal API](xref:fundamentals/minimal-apis) endpoint for weather data. +* `BlazorWebAppEntra`: Server-side project of the Blazor Web App. +* `BlazorWebAppEntra.Client`: Client-side project of the Blazor Web App. -Access the sample through the latest version folder in the Blazor samples repository with the following link. The sample is in the `BlazorWebAppEntra` folder for .NET 9 or later. +Access the sample through the latest version folder in the Blazor samples repository with the following link. The sample is in the `BlazorWebAppEntraBffYarpAspire` folder for .NET 9 or later. Start the solution from the ***`Aspire/Aspire.AppHost` project***. @@ -60,6 +74,14 @@ Create a client secret in the app's registration in the Entra or Azure portal (* Additional Entra configuration guidance for specific settings is provided later in this article. +## Aspire projects + +For more information on using Aspire and details on the `.AppHost` and `.ServiceDefaults` projects of the sample app, see the [Aspire documentation](/dotnet/aspire/). + +Confirm that you've met the prerequisites for Aspire. For more information, see the *Prerequisites* section of [Quickstart: Build your first Aspire solution](/dotnet/aspire/get-started/build-your-first-aspire-app?tabs=visual-studio#prerequisites). + +The sample app only configures an insecure HTTP launch profile (`http`) for use during development testing. For more information, including an example of insecure and secure launch settings profiles, see [Allow unsecure transport in Aspire (Aspire documentation)](/dotnet/aspire/troubleshooting/allow-unsecure-transport). + ## Server-side Blazor Web App project (`BlazorWebAppEntra`) The `BlazorWebAppEntra` project is the server-side project of the Blazor Web App. @@ -72,7 +94,7 @@ If the user needs to log in or out during client-side rendering, a full page rel ## Backend web API project (`MinimalApiJwt`) -The `MinimalApiJwt` project is a backend web API for multiple frontend projects. The project configures a [Minimal API](xref:fundamentals/minimal-apis) endpoint for weather data. +The `MinimalApiJwt` project is a backend web API for multiple frontend projects. The project configures a [Minimal API](xref:fundamentals/minimal-apis) endpoint for weather data. Requests from the Blazor Web App server-side project (`BlazorWebAppEntra`) are proxied to the `MinimalApiJwt` project. 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 . @@ -99,7 +121,7 @@ The of the call in the `MinimalApiJwt` project's `Program` file. +Configure the `MinimalApiJwt` project in the of the call in the project's `Program` file. For the web API app's registration, the `Weather.Get` scope is configured in the Entra or Azure portal in **Expose an API**. @@ -172,10 +194,10 @@ Obtain the application (client) ID, tenant (publisher) domain, and directory (te The authentication configuration depends on the type of tenant: -* [ME-ID tenant configuration](#me-id-tenant-configuration) -* [Microsoft Entra External ID configuration](#microsoft-entra-external-id-configuration) +* [Configuration for an ME-ID](#configuration-for-an-me-id) +* [Configuration for Microsoft Entra External ID](#configuration-for-microsoft-entra-external-id) -### ME-ID tenant configuration +### Configuration for an ME-ID *This section applies to an app registered in a Microsoft Entra ID or Azure AAD B2C tenant.* @@ -201,6 +223,12 @@ builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme) .AddDistributedTokenCaches(); ``` +Provide the same downstream API scope to the request transformer: + +```csharp +List scopes = ["{APP ID URI}/Weather.Get"]; +``` + Placeholders in the preceding configuration: * `{CLIENT ID (BLAZOR APP)}`: The application (client) ID. @@ -228,12 +256,19 @@ builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme) .AddDownstreamApi("DownstreamApi", configOptions => { configOptions.BaseUrl = "https://localhost:7277"; - configOptions.Scopes = ["api://11112222-bbbb-3333-cccc-4444dddd5555/Weather.Get"]; + configOptions.Scopes = + ["api://11112222-bbbb-3333-cccc-4444dddd5555/Weather.Get"]; }) .AddDistributedTokenCaches(); ``` -### Microsoft Entra External ID configuration +Example: + +```csharp +List scopes = ["api://11112222-bbbb-3333-cccc-4444dddd5555/Weather.Get"]; +``` + +### Configuration for Microsoft Entra External ID *This section applies to an app registered in a Microsoft Entra External ID tenant.* @@ -257,12 +292,18 @@ builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme) .AddDistributedTokenCaches(); ``` +Provide the same downstream API scope to the request transformer: + +```csharp +List scopes = ["{APP ID URI}/Weather.Get"]; +``` + Placeholders in the preceding configuration: * `{DIRECTORY NAME}`: The directory name of the tenant (publisher) domain. * `{CLIENT ID (BLAZOR APP)}`: The application (client) ID. * `{BASE ADDRESS}`: The web API's base address. -* `{APP ID URI}`: The App ID URI for web API scopes. Either of the following formats are used, where the `{CLIENT ID (WEB API)}` placeholder is the Client Id of the web API's Entra registration, and the `{DIRECTORY NAME}` placeholder is the directory name of the tenant (publisher) domain (example: `contoso`). +* `{APP ID URI}`: The App ID URI for web API scopes. Either of the following formats are used, where the `{CLIENT ID (WEB API)}` placeholder is the Client Id of the web API's Entra registration, and the `{DIRECTORY NAME}` placeholder is the directory name of the tenant (publishers) domain (example: `contoso`). * ME-ID or Microsoft Entra External ID tenant format: `api://{CLIENT ID (WEB API)}` * B2C tenant format: `https://{DIRECTORY NAME}.onmicrosoft.com/{CLIENT ID (WEB API)}` @@ -286,17 +327,17 @@ builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme) .AddDistributedTokenCaches(); ``` -The callback path (`CallbackPath`) must match the redirect URI (login callback path) configured when registering the application in the Entra or Azure portal. Paths are configured in the **Authentication** blade of the app's registration. The default value of `CallbackPath` is `/signin-oidc` for a registered redirect URI of `https://localhost/signin-oidc` (a port isn't required). - -The is the request path within the app's base path intercepted by the OpenID Connect handler where the user agent is first returned after signing out from Entra. The sample app doesn't set a value for the path because the default value of "`/signout-callback-oidc`" is used. After intercepting the request, the OpenID Connect handler redirects to the or , if specified. +Example: -[!INCLUDE[](~/blazor/security/includes/secure-authentication-flows.md)] +```csharp +List scopes = ["api://11112222-bbbb-3333-cccc-4444dddd5555/Weather.Get"]; +``` :::zone-end -:::zone pivot="bff-pattern" +:::zone pivot="without-yarp-and-aspire" -This version of the article covers implementing Entra with the [Backend for Frontend (BFF) pattern](/azure/architecture/patterns/backends-for-frontends). Change the article version selector to **Non-BFF pattern** if the app's specification doesn't call for adopting the BFF pattern. +This version of the article covers implementing Entra with the [Backend for Frontend (BFF) pattern](/azure/architecture/patterns/backends-for-frontends) without [YARP](https://dotnet.github.io/yarp/) and [Aspire](/dotnet/aspire/get-started/aspire-overview). Change the article version selector to **With YARP and Aspire** if the app's specification calls for adopting YARP and Aspire. The following specification is covered: @@ -304,30 +345,18 @@ The following specification is covered: * The server project calls to add a server-side authentication state provider that uses to flow the authentication state to the client. The client calls to deserialize and use the authentication state passed by the server. The authentication state is fixed for the lifetime of the WebAssembly application. * The app uses [Microsoft Entra ID](https://www.microsoft.com/security/business/microsoft-entra), based on [Microsoft Identity Web](/entra/msal/dotnet/microsoft-identity-web/) packages. * Automatic non-interactive token refresh is managed by the framework. -* The [Backend for Frontend (BFF) pattern](/azure/architecture/patterns/backends-for-frontends) is adopted using [Aspire](/dotnet/aspire/get-started/aspire-overview) for service discovery and [YARP](https://dotnet.github.io/yarp/) for proxying requests to a weather forecast endpoint on the backend app. - * A backend web API uses JWT-bearer authentication to validate JWT tokens saved by the Blazor Web App in the sign-in cookie. - * Aspire improves the experience of building .NET cloud-native apps. It provides a consistent, opinionated set of tools and patterns for building and running distributed apps. - * YARP (Yet Another Reverse Proxy) is a library used to create a reverse proxy server. -* The app uses server-side and client-side service abstractions to display generated weather data. +* The [Backend for Frontend (BFF) pattern](/azure/architecture/patterns/backends-for-frontends) is adopted for proxying requests to a weather forecast endpoint on the backend app. A backend web API uses JWT-bearer authentication to validate JWT tokens saved by the Blazor Web App in the sign-in cookie. +* The app uses server-side and client-side service abstractions to display generated weather data: * When rendering the `Weather` component on the server to display weather data, the component uses the `ServerWeatherForecaster`. Microsoft Identity Web packages provide API to create a named downstream web service for making web API calls. is injected into the `ServerWeatherForecaster`, which is used to call to obtain weather data from an external web API (`MinimalApiJwt` project). - * When the `Weather` 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's Minimal API (`/weather-forecast`) for weather data. The Minimal API endpoint obtains an access token for the user by calling . Along with the correct scopes, a reverse proxy call is made to the external web API (`MinimalApiJwt` project) to obtain and return weather data to the client for rendering by the component. - -## Prerequisites - -[Aspire](/dotnet/aspire/get-started/aspire-overview) requires [Visual Studio](https://visualstudio.microsoft.com/) version 17.10 or later. - -Also, see the *Prerequisites* section of [Quickstart: Build your first Aspire solution](/dotnet/aspire/get-started/build-your-first-aspire-app?tabs=visual-studio#prerequisites). + * When the `Weather` 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's Minimal API (`/weather-forecast`) for weather data. The Minimal API endpoint obtains the weather data from the `ServerWeatherForecaster` class and returns it to the client for rendering by the component. ## Sample solution The sample solution consists of the following projects: -* Aspire: - * `Aspire.AppHost`: Used to manage the high-level orchestration concerns of the app. - * `Aspire.ServiceDefaults`: Contains default Aspire app configurations that can be extended and customized as needed. -* `MinimalApiJwt`: Backend web API, containing an example [Minimal API](xref:fundamentals/minimal-apis) endpoint for weather data. -* `BlazorWebAppEntra`: Server-side project of the Blazor Web App. +* `BlazorWebAppEntra`: Server-side project of the Blazor Web App, containing an example [Minimal API](xref:fundamentals/minimal-apis) endpoint for weather data. * `BlazorWebAppEntra.Client`: Client-side project of the Blazor Web App. +* `MinimalApiJwt`: Backend web API, containing an example [Minimal API](xref:fundamentals/minimal-apis) endpoint for weather data. Access the sample through the latest version folder in the Blazor samples repository with the following link. The sample is in the `BlazorWebAppEntraBff` folder for .NET 9 or later. @@ -339,7 +368,7 @@ We recommend using separate registrations for apps and web APIs, even when the a Register the web API (`MinimalApiJwt`) first so that you can then grant access to the web API when registering the app. The web API's tenant ID and client ID are used to configure the web API in its `Program` file. After registering the web API, expose the web API in **App registrations** > **Expose an API** with a scope name of `Weather.Get`. Record the App ID URI for use in the app's configuration. -Next, register the app (`BlazorWebAppEntra`) with a **Web** platform configuration with two entries under **Redirect URI**: `https://localhost/signin-oidc` and `https://localhost/signout-callback-oidc` (ports aren't required on these URIs). The app's tenant ID, tenant domain, and client ID, along with the web API's base address, App ID URI, and weather scope name, are used to configure the app in its `appsettings.json` file. Grant API permission to access the web API in **App registrations** > **API permissions**. If the app's security specification calls for it, you can grant admin consent for the organization to access the web API. Authorized users and groups are assigned to the app's registration in **App registrations** > **Enterprise applications**. +Next, register the app (`BlazorWebAppEntra`) with a **Web** platform configuration with two entries under **Redirect URI**: `https://localhost/signin-oidc` and `https://localhost/signout-callback-oidc` (ports aren't required on these URIs). Set the **Front-channel logout URL** to `https://localhost/signout-callback-oidc` (a port isn't required). The app's tenant ID, tenant domain, and client ID, along with the web API's base address, App ID URI, and weather scope name, are used to configure the app in its `appsettings.json` file. Grant API permission to access the web API in **App registrations** > **API permissions**. If the app's security specification calls for it, you can grant admin consent for the organization to access the web API. Authorized users and groups are assigned to the app's registration in **App registrations** > **Enterprise applications**. In the Entra or Azure portal's **Implicit grant and hybrid flows** app registration configuration, don't select either checkbox for the authorization endpoint to return **Access tokens** or **ID tokens**. The OpenID Connect handler automatically requests the appropriate tokens using the code returned from the authorization endpoint. @@ -347,14 +376,6 @@ Create a client secret in the app's registration in the Entra or Azure portal (* Additional Entra configuration guidance for specific settings is provided later in this article. -## Aspire projects - -For more information on using Aspire and details on the `.AppHost` and `.ServiceDefaults` projects of the sample app, see the [Aspire documentation](/dotnet/aspire/). - -Confirm that you've met the prerequisites for Aspire. For more information, see the *Prerequisites* section of [Quickstart: Build your first Aspire solution](/dotnet/aspire/get-started/build-your-first-aspire-app?tabs=visual-studio#prerequisites). - -The sample app only configures an insecure HTTP launch profile (`http`) for use during development testing. For more information, including an example of insecure and secure launch settings profiles, see [Allow unsecure transport in Aspire (Aspire documentation)](/dotnet/aspire/troubleshooting/allow-unsecure-transport). - ## Server-side Blazor Web App project (`BlazorWebAppEntra`) The `BlazorWebAppEntra` project is the server-side project of the Blazor Web App. @@ -367,7 +388,7 @@ If the user needs to log in or out during client-side rendering, a full page rel ## Backend web API project (`MinimalApiJwt`) -The `MinimalApiJwt` project is a backend web API for multiple frontend projects. The project configures a [Minimal API](xref:fundamentals/minimal-apis) endpoint for weather data. Requests from the Blazor Web App server-side project (`BlazorWebAppEntra`) are proxied to the `MinimalApiJwt` project. +The `MinimalApiJwt` project is a backend web API for multiple frontend projects. The project configures a [Minimal API](xref:fundamentals/minimal-apis) endpoint for weather data. 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 . @@ -394,7 +415,7 @@ The of the call in the project's `Program` file. +Configure the project in the of the call in the `MinimalApiJwt` project's `Program` file. For the web API app's registration, the `Weather.Get` scope is configured in the Entra or Azure portal in **Expose an API**. @@ -467,10 +488,10 @@ Obtain the application (client) ID, tenant (publisher) domain, and directory (te The authentication configuration depends on the type of tenant: -* [Configuration for an ME-ID](#configuration-for-an-me-id) -* [Configuration for Microsoft Entra External ID](#configuration-for-microsoft-entra-external-id) +* [ME-ID tenant configuration](#me-id-tenant-configuration) +* [Microsoft Entra External ID configuration](#microsoft-entra-external-id-configuration) -### Configuration for an ME-ID +### ME-ID tenant configuration *This section applies to an app registered in a Microsoft Entra ID or Azure AAD B2C tenant.* @@ -496,12 +517,6 @@ builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme) .AddDistributedTokenCaches(); ``` -Provide the same downstream API scope to the request transformer: - -```csharp -List scopes = ["{APP ID URI}/Weather.Get"]; -``` - Placeholders in the preceding configuration: * `{CLIENT ID (BLAZOR APP)}`: The application (client) ID. @@ -529,19 +544,12 @@ builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme) .AddDownstreamApi("DownstreamApi", configOptions => { configOptions.BaseUrl = "https://localhost:7277"; - configOptions.Scopes = - ["api://11112222-bbbb-3333-cccc-4444dddd5555/Weather.Get"]; + configOptions.Scopes = ["api://11112222-bbbb-3333-cccc-4444dddd5555/Weather.Get"]; }) .AddDistributedTokenCaches(); ``` -Example: - -```csharp -List scopes = ["api://11112222-bbbb-3333-cccc-4444dddd5555/Weather.Get"]; -``` - -### Configuration for Microsoft Entra External ID +### Microsoft Entra External ID configuration *This section applies to an app registered in a Microsoft Entra External ID tenant.* @@ -565,18 +573,12 @@ builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme) .AddDistributedTokenCaches(); ``` -Provide the same downstream API scope to the request transformer: - -```csharp -List scopes = ["{APP ID URI}/Weather.Get"]; -``` - Placeholders in the preceding configuration: * `{DIRECTORY NAME}`: The directory name of the tenant (publisher) domain. * `{CLIENT ID (BLAZOR APP)}`: The application (client) ID. * `{BASE ADDRESS}`: The web API's base address. -* `{APP ID URI}`: The App ID URI for web API scopes. Either of the following formats are used, where the `{CLIENT ID (WEB API)}` placeholder is the Client Id of the web API's Entra registration, and the `{DIRECTORY NAME}` placeholder is the directory name of the tenant (publishers) domain (example: `contoso`). +* `{APP ID URI}`: The App ID URI for web API scopes. Either of the following formats are used, where the `{CLIENT ID (WEB API)}` placeholder is the Client Id of the web API's Entra registration, and the `{DIRECTORY NAME}` placeholder is the directory name of the tenant (publisher) domain (example: `contoso`). * ME-ID or Microsoft Entra External ID tenant format: `api://{CLIENT ID (WEB API)}` * B2C tenant format: `https://{DIRECTORY NAME}.onmicrosoft.com/{CLIENT ID (WEB API)}` @@ -600,11 +602,11 @@ builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme) .AddDistributedTokenCaches(); ``` -Example: +The callback path (`CallbackPath`) must match the redirect URI (login callback path) configured when registering the application in the Entra or Azure portal. Paths are configured in the **Authentication** blade of the app's registration. The default value of `CallbackPath` is `/signin-oidc` for a registered redirect URI of `https://localhost/signin-oidc` (a port isn't required). -```csharp -List scopes = ["api://11112222-bbbb-3333-cccc-4444dddd5555/Weather.Get"]; -``` +The is the request path within the app's base path intercepted by the OpenID Connect handler where the user agent is first returned after signing out from Entra. The sample app doesn't set a value for the path because the default value of "`/signout-callback-oidc`" is used. After intercepting the request, the OpenID Connect handler redirects to the or , if specified. + +[!INCLUDE[](~/blazor/security/includes/secure-authentication-flows.md)] :::zone-end @@ -1083,6 +1085,8 @@ For more information on using a shared Data Protection key ring and key storage * [Azure Storage documentation](/azure/storage/) * [Provide access to Key Vault keys, certificates, and secrets with Azure role-based access control](/azure/key-vault/general/rbac-guide?tabs=azure-cli) +:::zone pivot="with-yarp-and-aspire" + ## YARP forwarder destination prefix The Blazor Web App server project's YARP forwarder, where the user's access token is attached to the `MinimalApiJwt` web API call, specifies a destination prefix of `https://weatherapi`. This value matches the project name passed to in the `Program` file of the `Aspire.AppHost` project. @@ -1104,6 +1108,8 @@ var weatherApi = builder.AddProject("weatherapi"); There's no need to change the destination prefix of the YARP forwarder when deploying the Blazor Web App to production. The Microsoft Identity Web Downstream API package uses the base URI passed via configuration to make the web API call from the `ServerWeatherForecaster`, not the destination prefix of the YARP forwarder. In production, the YARP forwarder merely transforms the request, adding the user's access token. +:::zone-end + ## Redirect to the home page on logout 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. diff --git a/aspnetcore/security/authentication/configure-jwt-bearer-authentication.md b/aspnetcore/security/authentication/configure-jwt-bearer-authentication.md index 23a4e5831083..d53591fe172f 100644 --- a/aspnetcore/security/authentication/configure-jwt-bearer-authentication.md +++ b/aspnetcore/security/authentication/configure-jwt-bearer-authentication.md @@ -287,7 +287,7 @@ Some secure token servers encrypt the access tokens. Access tokens do not requir For Blazor examples that use YARP to implement the BFF pattern, see the following articles: -* +* * :::moniker-end diff --git a/aspnetcore/zone-pivot-groups.yml b/aspnetcore/zone-pivot-groups.yml index b6bbe21fb21c..6997c3588a16 100644 --- a/aspnetcore/zone-pivot-groups.yml +++ b/aspnetcore/zone-pivot-groups.yml @@ -104,10 +104,10 @@ groups: title: Specification prompt: Choose the app specification pivots: - - id: non-bff-pattern - title: Non-BFF pattern - - id: bff-pattern - title: BFF pattern + - id: with-yarp-and-aspire + title: With YARP and Aspire + - id: without-yarp-and-aspire + title: Without YARP and Aspire - id: unit-testing-framework title: Unit testing framework prompt: Choose a unit testing framework