Skip to content

Commit e77db03

Browse files
committed
Updates
1 parent 761ec6b commit e77db03

File tree

2 files changed

+52
-95
lines changed

2 files changed

+52
-95
lines changed

aspnetcore/blazor/call-web-api.md

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,8 @@ For client-side rendering (CSR), which includes Interactive WebAssembly componen
3737
builder.Services.AddScoped(sp =>
3838
new HttpClient
3939
{
40-
BaseAddress = new Uri(builder.Configuration["FrontendUrl"] ?? "https://localhost:5002")
40+
BaseAddress = new Uri(builder.Configuration["FrontendUrl"] ??
41+
"https://localhost:5002")
4142
});
4243
```
4344

@@ -108,7 +109,11 @@ The solution demonstrates calling a secure web API for the following:
108109

109110
### `BlazorWebAppOidc`
110111

111-
A Blazor Web App with global Auto interactivity that uses OIDC authentication with Microsoft Entra without using Entra-specific packages. The solution includes a demonstration of obtaining weather data securely via a web API when a component that adopts Interactive Auto rendering is rendered on the client.
112+
A Blazor Web App with global Auto interactivity that uses OIDC authentication with Microsoft Entra without using Entra-specific packages. The solution includes a demonstration of obtaining weather data securely via a web API. <!-- The sample demonstrates how to [pass an access token](xref:blazor/security/additional-scenarios#pass-tokens-to-a-server-side-blazor-app) to call a secure web API. -->
113+
114+
### `BlazorWebAppOidcServer`
115+
116+
A Blazor Web App with global Interactive Server interactivity that uses OIDC authentication with Microsoft Entra without using Entra-specific packages. The sample demonstrates how to [pass an access token](xref:blazor/security/additional-scenarios#pass-tokens-to-a-server-side-blazor-app) to call a secure web API.
112117

113118
### `BlazorWebAppOidcBff`
114119

@@ -127,6 +132,14 @@ The solution includes a demonstration of obtaining weather data securely via a w
127132

128133
A Blazor Web App with global Auto interactivity that uses [Microsoft identity platform](/entra/identity-platform/)/[Microsoft Identity Web packages](/entra/msal/dotnet/microsoft-identity-web/) for [Microsoft Entra ID](https://www.microsoft.com/security/business/microsoft-entra). The solution includes a demonstration of obtaining weather data securely via a web API when a component that adopts Interactive Auto rendering is rendered on the client.
129134

135+
<!--
136+
137+
### `BlazorWebAppEntraServer`
138+
139+
A Blazor Web App with global Interactive Server interactivity that uses Microsoft Identity Web with Microsoft Entra-specific packages. The sample demonstrates how to [pass an access token](xref:blazor/security/additional-scenarios#pass-tokens-to-a-server-side-blazor-app) to call a secure web API.
140+
141+
-->
142+
130143
### `BlazorWebAppEntraBff`
131144

132145
A Blazor Web App with global Auto interactivity that uses:

aspnetcore/blazor/security/additional-scenarios.md

Lines changed: 37 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -21,17 +21,9 @@ This article explains how to configure server-side Blazor for additional securit
2121

2222
:::moniker range=">= aspnetcore-8.0"
2323

24-
For Blazor Web Apps, guidance in this section on how to pass tokens to Razor components should be addressed by [Update section on passing tokens in Blazor Web Apps (`dotnet/AspNetCore.Docs` #31691)](https://github.com/dotnet/AspNetCore.Docs/issues/31691) in 2025.
24+
*This section applies to Blazor Web Apps. For Blazor Server, view the [7.0 version of this article section](xref:blazor/security/additional-scenarios?view=aspnetcore-7.0&preserve-view=true#pass-tokens-to-a-server-side-blazor-app).*
2525

26-
For more information, see the following issues:
27-
28-
* [Access `AuthenticationStateProvider` in outgoing request middleware (`dotnet/aspnetcore` #52379)](https://github.com/dotnet/aspnetcore/issues/52379): This is the current issue to address passing tokens in Blazor Web Apps with framework features, which will probably be addressed for .NET 11 (late 2026).
29-
* [Problem providing Access Token to HttpClient in Interactive Server mode (`dotnet/aspnetcore` #52390)](https://github.com/dotnet/aspnetcore/issues/52390): This issue was closed as a duplicate of the preceding issue, but it contains helpful discussion and potential workaround strategies.
30-
31-
For Blazor Server, view the [7.0 version of this article section](xref:blazor/security/additional-scenarios?view=aspnetcore-7.0&preserve-view=true#pass-tokens-to-a-server-side-blazor-app).
32-
33-
<!--
34-
Tokens available outside of the Razor components in a Blazor Web App can be passed to components with the approach described in this section. The example in this section focuses on passing access and refresh tokens, but the approach is valid for other HTTP context state provided by <xref:Microsoft.AspNetCore.Http.HttpContext>.
26+
Tokens available outside of the Razor components in a Blazor Web App can be passed to interactive components with the approaches described in this section. The examples in this section focus on passing access tokens, but the approach is valid for other HTTP context state provided by <xref:Microsoft.AspNetCore.Http.HttpContext>.
3527

3628
> [!NOTE]
3729
> Passing the [anti-request forgery (CSRF/XSRF) token](xref:security/anti-request-forgery) to Razor components is useful in scenarios where components POST to Identity or other endpoints that require validation. However, don't follow the guidance in this section for processing form POST requests or web API requests with XSRF support. The Blazor framework provides built-in antiforgery support for forms and calling web APIs. For more information, see the following resources:
@@ -40,111 +32,63 @@ Tokens available outside of the Razor components in a Blazor Web App can be pass
4032
> * Antiforgery support for forms: <xref:blazor/forms/index#antiforgery-support>
4133
> * Antiforgery support for web API: <xref:blazor/call-web-api#antiforgery-support>
4234
43-
Authenticate the app as you would with a regular Razor Pages or MVC app. Provision and save the tokens to the authentication cookie.
44-
45-
In the `Program` file:
46-
47-
```csharp
48-
using Microsoft.AspNetCore.Authentication.OpenIdConnect;
49-
using Microsoft.IdentityModel.Protocols.OpenIdConnect;
50-
51-
...
35+
Reading tokens from the <xref:Microsoft.AspNetCore.Http.HttpContext> using <xref:Microsoft.AspNetCore.Http.IHttpContextAccessor> is a reasonable approach for obtaining tokens during interactive server rendering. However, tokens aren't updated if the user authenticates after the circuit is established, since the <xref:Microsoft.AspNetCore.Http.HttpContext> is captured at the start of the SignalR connection. Also, the use of <xref:System.Threading.AsyncLocal%601> by <xref:Microsoft.AspNetCore.Http.IHttpContextAccessor> means that you must be careful not to lose the execution context before reading the <xref:Microsoft.AspNetCore.Http.HttpContext>.
5236

53-
builder.Services.Configure<OpenIdConnectOptions>(
54-
OpenIdConnectDefaults.AuthenticationScheme, options =>
55-
{
56-
options.ResponseType = OpenIdConnectResponseType.Code;
57-
options.SaveTokens = true;
58-
options.Scope.Add(OpenIdConnectScope.OfflineAccess);
59-
});
60-
```
37+
### Blazor Web App that adopts global Interactive Server rendering
6138

62-
<xref:Microsoft.AspNetCore.Authentication.OpenIdConnect?displayProperty=fullName> and <xref:Microsoft.IdentityModel.Protocols.OpenIdConnect?displayProperty=fullName> API is provided by the [`Microsoft.AspNetCore.Authentication.OpenIdConnect`](https://www.nuget.org/packages/Microsoft.AspNetCore.Authentication.OpenIdConnect) NuGet package.
39+
Subclass <xref:System.Net.Http.DelegatingHandler> to attach 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.
6340

64-
[!INCLUDE[](~/includes/package-reference.md)]
41+
`TokenHandler.cs`:
6542

66-
Optionally, additional scopes are added with `options.Scope.Add("{SCOPE}");`, where the `{SCOPE}` placeholder is the additional scope to add.
43+
```csharp
44+
using System.Net.Http.Headers;
45+
using Microsoft.AspNetCore.Authentication;
6746

68-
Define a token provider service that can be used within the Blazor app to resolve the tokens from [dependency injection (DI)](xref:blazor/fundamentals/dependency-injection).
47+
public class TokenHandler(IHttpContextAccessor httpContextAccessor) :
48+
DelegatingHandler
49+
{
50+
protected override async Task<HttpResponseMessage> SendAsync(
51+
HttpRequestMessage request, CancellationToken cancellationToken)
52+
{
53+
var accessToken = httpContextAccessor.HttpContext?
54+
.GetTokenAsync("access_token").Result ??
55+
throw new Exception("No access token");
6956

70-
`TokenProvider.cs`:
57+
request.Headers.Authorization =
58+
new AuthenticationHeaderValue("Bearer", accessToken);
7159

72-
```csharp
73-
public class TokenProvider
74-
{
75-
public string? AccessToken { get; set; }
76-
public string? RefreshToken { get; set; }
60+
return await base.SendAsync(request, cancellationToken);
61+
}
7762
}
7863
```
7964

80-
In the `Program` file, add services for:
65+
In the project's `Program` file, the token handler (`TokenHandler`) is registered as a scoped service and specified as a [named HTTP client's](xref:blazor/call-web-api#named-httpclient-with-ihttpclientfactory) message handler with <xref:Microsoft.Extensions.DependencyInjection.HttpClientBuilderExtensions.AddHttpMessageHandler%2A>.
8166

82-
* <xref:System.Net.Http.IHttpClientFactory>: Used in service classes to obtain data from a server API with an access token. The example in this section is a weather forecast data service (`WeatherForecastService`) that requires an access token.
83-
* `TokenProvider`: Holds the access and refresh tokens. Register the token provider service as a ***scoped*** service.
84-
85-
```csharp
86-
builder.Services.AddHttpClient();
87-
builder.Services.AddScoped<TokenProvider>();
88-
```
67+
In the following example, the `{HTTP CLIENT NAME}` placeholder is the name of the <xref:System.Net.Http.HttpClient>, and the `{BASE ADDRESS}` placeholder is the web API's base address URI.
8968

90-
In the `App` component (`Components/App.razor`), resolve the service and initialize it with the data from [`HttpContext` as a cascaded parameter](xref:blazor/security/index#avoid-ihttpcontextaccessorhttpcontext-in-razor-components):
69+
In `Program.cs`:
9170

92-
```razor
93-
@inject TokenProvider TokenProvider
94-
95-
...
96-
97-
@code {
98-
[CascadingParameter]
99-
public HttpContext? HttpContext { get; set; }
100-
101-
protected override Task OnInitializedAsync()
102-
{
103-
TokenProvider.AccessToken = await HttpContext.GetTokenAsync("access_token");
104-
TokenProvider.RefreshToken = await HttpContext.GetTokenAsync("refresh_token");
71+
```csharp
72+
builder.Services.AddScoped<TokenHandler>();
10573

106-
return base.OnInitializedAsync();
107-
}
108-
}
74+
builder.Services.AddHttpClient("{HTTP CLIENT NAME}",
75+
client => client.BaseAddress = new Uri("{BASE ADDRESS}"))
76+
.AddHttpMessageHandler<TokenHandler>();
10977
```
11078

111-
In the service that makes a secure API request, inject the token provider and retrieve the token for the API request:
79+
> [!NOTE]
80+
> You can supply the HTTP client base address from [configuration](xref:blazor/fundamentals/configuration) with `builder.Configuration["{CONFIGURATION KEY}"]`, where the `{CONFIGURATION KEY}` placeholder is the configuration key.
11281
113-
`WeatherForecastService.cs`:
82+
An <xref:System.Net.Http.HttpClient> created by a component can make secure web API requests. In the following example, the `{REQUEST URI}` is the relative request URI, and the `{HTTP CLIENT NAME}` placeholder is the name of the <xref:System.Net.Http.HttpClient>:
11483

11584
```csharp
116-
using System;
117-
using System.Net.Http;
118-
using System.Threading.Tasks;
119-
120-
public class WeatherForecastService
121-
{
122-
private readonly HttpClient http;
123-
private readonly TokenProvider tokenProvider;
85+
var request = new HttpRequestMessage(HttpMethod.Get, "{REQUEST URI}");
86+
var client = ClientFactory.CreateClient("{HTTP CLIENT NAME}");
12487

125-
public WeatherForecastService(IHttpClientFactory clientFactory,
126-
TokenProvider tokenProvider)
127-
{
128-
http = clientFactory.CreateClient();
129-
this.tokenProvider = tokenProvider;
130-
}
131-
132-
public async Task<WeatherForecast[]> GetForecastAsync()
133-
{
134-
var token = tokenProvider.AccessToken;
135-
var request = new HttpRequestMessage(HttpMethod.Get,
136-
"https://localhost:5003/WeatherForecast");
137-
request.Headers.Add("Authorization", $"Bearer {token}");
138-
var response = await http.SendAsync(request);
139-
response.EnsureSuccessStatusCode();
140-
141-
return await response.Content.ReadFromJsonAsync<WeatherForecast[]>() ??
142-
Array.Empty<WeatherForecast>();
143-
}
144-
}
88+
var response = await client.SendAsync(request);
14589
```
14690

147-
-->
91+
Additional features are planned for Blazor, which is tracked by [Access `AuthenticationStateProvider` in outgoing request middleware (`dotnet/aspnetcore` #52379)](https://github.com/dotnet/aspnetcore/issues/52379), which will probably be addressed for .NET 11 (late 2026). [Problem providing Access Token to HttpClient in Interactive Server mode (`dotnet/aspnetcore` #52390)](https://github.com/dotnet/aspnetcore/issues/52390) is a closed issue that contains helpful discussion and potential workaround strategies for advanced use cases.
14892

14993
:::moniker-end
15094

0 commit comments

Comments
 (0)