Add SenderAuthCookieHandler for cookie-based JWT auth
Added a custom DelegatingHandler, SenderAuthCookieHandler, to forward the browser's Cookie header to outgoing HttpClient requests in Blazor Server. Registered the handler as a transient service and integrated it into the named HttpClient pipeline for internal API calls. This enables Blazor Server components to make authenticated API calls using cookie-based JWT authentication (AuthScheme.Sender).
This commit is contained in:
@@ -0,0 +1,33 @@
|
||||
namespace EnvelopeGenerator.Server.Handlers;
|
||||
|
||||
/// <summary>
|
||||
/// A <see cref="DelegatingHandler"/> that forwards the incoming HTTP request's
|
||||
/// <c>Cookie</c> header to all outgoing <see cref="System.Net.Http.HttpClient"/> calls
|
||||
/// made by Blazor Server components.
|
||||
///
|
||||
/// Problem it solves:
|
||||
/// Blazor Server runs on the server process. When a component calls an API endpoint
|
||||
/// that requires cookie-based JWT authentication (AuthScheme.Sender), the HttpClient
|
||||
/// does not automatically include the browser's cookies — those only travel with
|
||||
/// browser-initiated requests. This handler copies the <c>Cookie</c> header from the
|
||||
/// current <see cref="IHttpContextAccessor.HttpContext"/> into every outgoing request
|
||||
/// so that the API's JwtBearer <c>OnMessageReceived</c> callback can extract the token.
|
||||
///
|
||||
/// Thread safety:
|
||||
/// The handler is registered as Transient and is resolved per-request by the
|
||||
/// IHttpClientFactory pipeline, so there is no shared state between requests.
|
||||
/// </summary>
|
||||
public class SenderAuthCookieHandler(IHttpContextAccessor httpContextAccessor) : DelegatingHandler
|
||||
{
|
||||
protected override Task<HttpResponseMessage> SendAsync(
|
||||
HttpRequestMessage request,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var cookieHeader = httpContextAccessor.HttpContext?.Request.Headers["Cookie"].ToString();
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(cookieHeader))
|
||||
request.Headers.TryAddWithoutValidation("Cookie", cookieHeader);
|
||||
|
||||
return base.SendAsync(request, cancellationToken);
|
||||
}
|
||||
}
|
||||
@@ -69,6 +69,9 @@ try
|
||||
builder.Services.AddHttpContextAccessor();
|
||||
|
||||
// Named HttpClient for internal API calls
|
||||
// SenderAuthCookieHandler forwards the browser's Cookie header so that
|
||||
// Blazor Server components can call cookie-authenticated endpoints (AuthScheme.Sender).
|
||||
builder.Services.AddTransient<EnvelopeGenerator.Server.Handlers.SenderAuthCookieHandler>();
|
||||
builder.Services.AddHttpClient("EnvelopeGenerator.Server", (sp, client) =>
|
||||
{
|
||||
var httpContextAccessor = sp.GetRequiredService<IHttpContextAccessor>();
|
||||
@@ -79,7 +82,8 @@ try
|
||||
// Set base address to current host for SSR scenarios
|
||||
client.BaseAddress = new Uri($"{request.Scheme}://{request.Host}");
|
||||
}
|
||||
});
|
||||
})
|
||||
.AddHttpMessageHandler<EnvelopeGenerator.Server.Handlers.SenderAuthCookieHandler>();
|
||||
|
||||
// CORS Policy
|
||||
var allowedOrigins = config.GetSection("AllowedOrigins").Get<string[]>() ??
|
||||
|
||||
Reference in New Issue
Block a user