Search code examples
c#authenticationkeycloakwebassembly.net-7.0

Keycloak with .NET WASM and .NET API


I have Keycloak running in a docker container, a .NET 7 WASM PWA project (standalone, client only, no server) and a .NET 7 API server.

I can authenticate against Keycloak and show permissions with the WASM project and I can authenticate via swagger in the API server and then call Authorize Controller endpoints.

But I cannot transfer the JWT from the WASM project to the API.

I tried and followed thies great tutorial: https://nikiforovall.github.io/blazor/dotnet/2022/12/08/dotnet-keycloak-blazorwasm-auth.html and even downloaded the source code. Everything works fine, but it is an WASM server project, not a standalone project with API server like I have.

I can recreate the problem with an MWE, so I can make sure none of my boiler plate code is creating the issue. Looking at a Fiddler log, I could see that the JWT is not transferred: enter image description here I would expect an authorize: Bearer, but it is missing.

On the WASM client I added

builder.Services.AddHttpClient(httpClientName, client => client.BaseAddress = new Uri(baseAddress)).AddHttpMessageHandler<BaseAddressAuthorizationMessageHandler>();
builder.Services.AddScoped(sp => sp.GetRequiredService<IHttpClientFactory>().CreateClient(httpClientName));

This should append the token to outgoing messages, like documented here, but it doesn't.

Edit: I am almost certain, that the reason the JWT is not automatically added to outgoing messages is because of Access tokens are only added when the request URI is within the app's base URI.

How can I change the BaseUri in Blazor WASM application to my Web API? Setting the BaseUri in the HttpClient is not doing the trick.


Solution

  • The solution is to implement and use CustomAuthorizationMessageHandler from here with the URI to the Web API:

    public class CustomAuthorizationMessageHandler : AuthorizationMessageHandler
    {
        public CustomAuthorizationMessageHandler(IAccessTokenProvider provider, 
            NavigationManager navigation)
            : base(provider, navigation)
        {
            ConfigureHandler(authorizedUrls: new[] { webApiUri });
        }
    }