serilog-sinks-browserhttp icon indicating copy to clipboard operation
serilog-sinks-browserhttp copied to clipboard

How to add authentication header to HTTP requests created by BrowserHttpSink?

Open szmalec opened this issue 5 years ago • 2 comments

I would like logs generated for an authenticated user to be sent to the server along with the user's token in the headers. If the user signs off, log entries should be sent to the server without this token.

Scenario: I am using Serilog.Sinks.BrowserHttp in my Blazor WASM app:

Log.Logger = new LoggerConfiguration()
    .WriteTo.BrowserHttp()
    .CreateLogger();

try {
    Log.Information("Starting app ({clientAppVersion})...", typeof(Program).Assembly.GetName().Version);
    // https://devblogs.microsoft.com/aspnet/blazor-webassembly-3-2-0-preview-1-release-now-available/
    var builder = WebAssemblyHostBuilder.CreateDefault(args);
    builder.Services.AddSingleton<MyCustomJwtAuthService>();
    //...
    builder.RootComponents.Add<App>("app");
    await builder.Build().RunAsync();
}
catch (Exception ex)
{
    Log.Fatal(ex, "An exception occurred while creating the WASM host");
    throw;
}

My app uses some king MyCustomJwtAuthService (which is also used in my custom AuthenticationStateProvider implementation) which holds JWT token for currently signed in user (it also silently refreshes token). This JWT token is added to headers (_httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);) - so when HttpClient is used then HTTP requests are authenticated. As I can see in sources Blazor registers in DI singleton for HttpClient, but BrowserHttpSink creates its own HttpClient instance and Authorization header added by MyCustomJwtAuthService does not affect HttpClient instance created in BrowserHttpSink - so I can not extract authenticated user data from requests perfomed by BrowserHttpSink... I know that BrowserHttpSink accepts HttpMessageHandler as parameter but there are probably some issues related to used in Blazor WasmHttpMessageHandler (eg. see how folks are creating instances here). Maybe it would be better for BrowserHttpSink to take a parameter of type Func<HttpClient> - so that I could somehow decide whether to provide an instance created by DI or maybe a temporary instance before the DI system produces the correct instance for me? Although this may also not be ideal, because logs are sent to the server with a delay, so logs generated for an authenticated user can be sent after logging out ...

Any suggestions?

szmalec avatar Feb 14 '20 09:02 szmalec