diff --git a/EnvelopeGenerator.Server/EnvelopeGenerator.Server/Handlers/SenderAuthCookieHandler.cs b/EnvelopeGenerator.Server/EnvelopeGenerator.Server/Handlers/SenderAuthCookieHandler.cs new file mode 100644 index 00000000..27ea8c08 --- /dev/null +++ b/EnvelopeGenerator.Server/EnvelopeGenerator.Server/Handlers/SenderAuthCookieHandler.cs @@ -0,0 +1,33 @@ +namespace EnvelopeGenerator.Server.Handlers; + +/// +/// A that forwards the incoming HTTP request's +/// Cookie header to all outgoing 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 Cookie header from the +/// current into every outgoing request +/// so that the API's JwtBearer OnMessageReceived 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. +/// +public class SenderAuthCookieHandler(IHttpContextAccessor httpContextAccessor) : DelegatingHandler +{ + protected override Task 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); + } +} diff --git a/EnvelopeGenerator.Server/EnvelopeGenerator.Server/Program.cs b/EnvelopeGenerator.Server/EnvelopeGenerator.Server/Program.cs index fbdb824c..0a0769c6 100644 --- a/EnvelopeGenerator.Server/EnvelopeGenerator.Server/Program.cs +++ b/EnvelopeGenerator.Server/EnvelopeGenerator.Server/Program.cs @@ -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(); builder.Services.AddHttpClient("EnvelopeGenerator.Server", (sp, client) => { var httpContextAccessor = sp.GetRequiredService(); @@ -79,7 +82,8 @@ try // Set base address to current host for SSR scenarios client.BaseAddress = new Uri($"{request.Scheme}://{request.Host}"); } - }); + }) + .AddHttpMessageHandler(); // CORS Policy var allowedOrigins = config.GetSection("AllowedOrigins").Get() ??