Quantcast
Channel: Active questions tagged blazor - Stack Overflow
Viewing all articles
Browse latest Browse all 4839

Questions about Authentication with Blazor Web App (Interactive Render Mode = Auto)

$
0
0

I have some doubts and issues regarding the implementation of authentication in a Blazor Web App (Interactive Render Mode = Auto), and I'd appreciate your help in clarifying a few points.

Thanks in advance to everyone who helps.

First, a quick backstory for context:Imagine that I already have a .NET solution with several backend services that are ready and working. Services A, B, C, etc., already have all the APIs and their respective layers (clean architecture) coded. The entire JWT security scheme is functioning, and authorization with roles and claims is fully validated.

Separately from these services, I also have all the libraries with contracts (requests and responses) and HTTP services to consume these APIs. Again, everything is tested and working well up to this point.

Therefore, both authentication and authorization, as well as all backend services, are fine and won't be changed.

Now, I'm starting a Blazor Web App project (Interactive Render Mode = Auto) to consume some parts of the already implemented APIs. Disabling the security on my APIs, the consumption via Blazor is already working too.

The UI is ready, Blazor is calling and consuming the APIs.The doubts and issues specifically relate to authentication.The challenge here pertains exclusively to Interactive Render Mode = Auto.

To make it easier to understand, I'll refer to the two Blazor projects as:

  • WebApp.Server
  • WebApp.Client

An important point: I'm not using Identity.

My login page, along with all other pages, was created in the WebApp.Client project (following the MudBlazor template, where Layout, Route, and pages are all in WebApp.Client).

As we know, even though the page is located in the WebApp.Client project, it is not necessarily in WebAssembly mode. It switches between modes.

And here comes the challenge.If I implement everything in WebAssembly mode, I receive the token and the refresh token from my authentication API (on the login page), store them in localStorage, call NotifyAuthenticationStateChanged, and through a DelegatingHandler, the bearer token is always sent in HTTP calls.

It works!But not in the way it should, after all, we could also be in Server mode.

So, I would say that to make it work using only WebAssembly mode, it would be enough to implement a class inheriting from AuthenticationStateProvider, and everything would work correctly.But it won’t work in Server mode.

So, let's look at an implementation in WebApp.Server.

In Server mode, I implemented classes inheriting from RevalidatingServerAuthenticationStateProvider or ServerAuthenticationStateProvider.Both work as well, but only in Server mode.In this case, it stops working when we switch to WebAssembly mode, and WebAssembly mode doesn’t consider the application authenticated.

In this mode, I call the following code via a controller through the login page of WebApp.Client:

await HttpContext.SignInAsync(    CookieAuthenticationDefaults.AuthenticationScheme,    new ClaimsPrincipal(claimsIdentity),    new AuthenticationProperties    {        AllowRefresh = true,        IsPersistent = true,    });

Exactly because the login page is in WebApp.Client, I don’t have access to IHttpContextAccessor.

Another point: in Server mode, I can't write to localStorage, for example.Even if I use ProtectedLocalStorage, it’s a class from Microsoft.AspNetCore.Components.Server.dll, and my page is in WebApp.Client.If I write the information to encrypted localStorage, in WebAssembly mode, I won’t be able to use it correctly.

To get the Server to inform the Client about the authentication, I had to modify the implementation again.In this case, I changed the implementation of AuthenticationStateProvider in WebApp.Client and started using PersistentComponentState.In this case, I can keep my WebAssembly application authenticated just like the Server, but how do I receive the token from the server?

I found it very strange to have to pass the token via Claim on the Server:

state.PersistAsJson(nameof(UserInfo), userInfo);

To be able to retrieve this information on the Client and write it to localStorage.This seems quite wrong.

With the token received (in what I believe is the wrong way from Blazor.Server to Blazor.Client) and written to local storage, the APIs start receiving the bearer token and work correctly.

But then we have another problem, which is the refresh token.

In Angular, I used to code a timer that, when there were X minutes left before expiration, a call was made to receive the new access token, updating localStorage.Is there another way to do this in Blazor?And even if I do it the same way, when receiving the updated access token, WebApp.Server won’t have this new updated token (because I wrote it to localStorage), and if we fall back to Server mode, the APIs won’t be accessed anymore.

I think I managed to give some context to my problems and doubts.The examples out there only seem to work in one mode (either Server or Client).And also using Identity (which is not my case).

It also makes a difference in implementations when the login page is kept in the Blazor.Server project instead of the Blazor.Client project.

If anyone can shed some light or provide a good example on GitHub, I would greatly appreciate it.I’ve been searching quite a bit but haven’t found anything that works under my project conditions.

Thanks.


Viewing all articles
Browse latest Browse all 4839

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>