Take a look at the new features for authentication and authorization included in .NET 9.0!
Read more…
Brought to you by @andrea.chiarelli
Take a look at the new features for authentication and authorization included in .NET 9.0!
Read more…
Brought to you by @andrea.chiarelli
Share your thoughts about these new features!
Hi Andrea, thanks for the article.
Just to be clear regarding Authentication State Serialization for Blazor Web Apps, does this mean we can simply delete the following classes from your .NET 8 example Syncing the Authentication State :
UserInfo
PersistingRevalidatingAuthenticationStateProvider
PersistentAuthenticationStateProvider
and simply replace them with the new serialization/deserialization methods, as per your article?
AddAuthenticationStateSerialization
AddAuthenticationStateDeserialization
Hi @grantcolley,
Yes! You can get rid of those classes and use the builtin ones
Hi @andrea.chiarelli ,
Thanks for your great article.
When using an external API for credentials (with JWT) in a Blazor WebApp globally InteractiveAuto mode, I need to create a custom AuthenticationStateProvider
to manage the authentication state. In this scenario, even when using AddAuthenticationStateSerialization
and AddAuthenticationStateDeserialization
, components in Interactive WebAssembly mode attempt to retrieve the authentication state from the GetAuthenticationStateAsync()
method override in the CustomAuthenticationStateProvider
. In other words, they do not utilize the deserialized persistent authentication state.
I read your article, ‘Add Auth0 Authentication to Blazor Web Apps,’ where you used Auth0. However, in my project, I intend to use an external API and JWT for credentials.
Do you have any suggestions or ideas on how to handle this?
Hi @mshahabfar,
Thank you for reading my article and welcome to the Auth0 Community!
Sorry, I’m not sure I correctly understand your question. Are you saying that AddAuthenticationStateSerialization
and AddAuthenticationStateDeserialization
are not working as expected?
Also, is your application using InteractiveAuto mode or Interactive WebAssembly mode?
If you can share some code, I can try to help.
To call an external API, I suggest using the approach shown in this article.
Hi @andrea.chiarelli
Thank you for your reply.
I think I did not explain my problem clearly. Let me try to provide a more detailed and precise explanation.
As you know the Visual Studio 2022 Blazor WebApp sample template for Auto Interactive render mode with Individual Accounts as authentication type uses ASP.NET Core Identity. In this setup, it generates a set of pages in a static server-side rendering mode, also known as Prerendering mode, and utilizes ASP NET Core Identity classes such as SignInManager
and UserManager
to handle authentication. It does not create a custom AuthenticationStateProvider
(as all related tasks appear to be handled internally). Instead, it uses AddAuthenticationStateSerialization()
and AddAuthenticationStateDeserialization()
to transfer the authentication state from Prerendering mode to Interactive rendering mode.
I want to use a similar approach but with an external (remote) API for authentication. This means my Blazor WebApp project will not include ASP NET Core Identity. Instead, I will retrieve a JWT from an external API when the user successfully authenticates. I would like to follow the VS template’s approach by keeping my login and register Razor pages in static server-side rendering mode and transferring the authentication state to Interactive rendering mode using the mentioned serialization methods.
But it seems that to manually notify the Authentication State change or also store a JWT in local storage or a cookie, I need to create a custom AuthenticationStateProvider
. However, when my Blazor app is in interactive mode, it attempts to retrieve the authentication state from the overridden GetAuthenticationStateAsync()
method in my custom provider, rather than using the already persisted state provided by AddAuthenticationStateSerialization()
.
Please review the sample project I have shared with you at the following link :
my sample project
Thank you for your assistance!
Hey @mshahabfar,
Thank you for providing additional context.
Honestly, this is a scenario I’m not used to. At a very first look, I assume you should be allowed to do this (i.e., build your custom authentication state and ask its serialization and deserialization), but frankly AddAuthenticationStateSerialization()
and AddAuthenticationStateDeserialization()
are pretty new and I don’t know if they have any limitations and/or bugs right now.
I would need to analyze and debug your code to see if there is something wrong with it and I hope to do it in the next few days.
However, I noticed a few things that left me puzzled in your Program.cs:
builder.Services.AddAuthentication();
Why are you calling both AddAuthorizationCore()
here and AddAuthorization()
here?
Why two different registrations of the same CustomAuthenticationStateProvider
class (here and here)?
Not sure if they have an impact on the behavior of the code, but they don’t look like a standard approach.
Hey @andrea.chiarelli ,
Thank you for your time.
Like the official Visual Studio Blazor template, I want my login page to be in static server-side rendering mode (prerendering). One way to transfer the authentication state from prerendering to interactive rendering mode is by using the persisting component state. The Visual Studio template uses this approach with ASP NET Core Identity. However, they don’t provide samples demonstrating the use of an external API for this purpose (e.g., JWT).
In most cases, local storage is introduced as a solution, but this method doesn’t work for me because my login page exists only in prerendering mode. Therefore, I am looking for a way to adapt JWT-based remote authorization using the persisting component state approach. In Blazor 9.0, this process has been simplified with the introduction of AddAuthenticationStateSerialization()
and AddAuthenticationStateDeserialization()
.
Yes, I am aware there are some issues in my sample code, but those sections are planned for a later step. At the moment, my focus is on finding a way to transfer the authentication state to the interactive rendering mode.
Thank you
I figured out my problem using the approach I intended. Now I can handle user authentication using an external API that returns a JWT (access token) upon successful authentication. The login Razor page of my Blazor WebApp project (in auto-rendering mode) is a static SSR page. The authentication state is then transferred to the interactive rendering mode using the new Blazor 9.0 APIs: AddAuthenticationStateSerialization()
and AddAuthenticationStateDeserialization()
.
Here is my solution as a minimal repo, which demonstrates how these features can be implemented.
Awesome! Thank you for sharing @mshahabfar
I created a simple dotnet9 Blazor WebApp repo that uses the Auth0 packages here:
here
Hey @274188A, thank you for sharing!
I am trying to find the points where I can add my own custom claims for both the server and WebAssembly projects. At one point I understood the Persisting/Persisted approach, but that’s gone now (or it’s been replaced).
From what I understand, the server side can use an IClaimsTransformation (but that appears to get called 20 times in a row!) and the WebAssembly can use a CustomAuthenticationStateProvider.
I can’t figure out how to tie these into the Auth0 authentication implementation you created (which works really great) for InteractiveAuto, or if they are even the correct approach at this point.
I can’t use Auth0 claims, these have to come from my app.
Is there any sample code or pointers for the next chapter in this Auth0/Blazor/InteractiveAuto story as it relates to adding custom claims after the authentication is complete?
Thanks in advance.
Bill
Hi @nhwilly,
If I correctly understand your request, to add your custom claims, you can use a Custom Authentication State provider on the server too. Customer Authentication State providers are not only for Blazor WebAssembly. Or am I missing something?
No, I just didn’t understand it.
There have been so many approaches to this subject coming so quickly that I was confused about which parts I needed to add and which I didn’t. Lots of contradicting documentation, depending on which month you read it.
For anyone else here, the SDK and Blazor allow you to just use the AuthenticationState
on the webAssembly side. You don’t really have to do anything. It just works.
My plan was to create some bespoke custom AuthenticationStateData
and other things, but it got ugly pretty fast. I could get it to work on the server side, but the background deserialization on the webAssembly client is happening somewhere and I just couldn’t figure out how to inspect/intercept/modify it. It always uses AuthenticationStateData
no matter what I send it. I could write a JSON converter, but the more I worked, the more work there was.
In the end, I just reverted to a permission
claim value that is delimited with the additional information I need.
I’m letting the platform do its thing and working inside that. Not exactly what I wanted, but it’ll work.
Thanks for these articles - they restore my faith in Blazor.
I’ve reached an interesting point, now that I’ve tried all the approaches I can think of. If you know of any other way to achieve what I’m trying to do, I’d love to hear it.
Goal: To have an Auth0 identity that represents the user and add an additional ClaimsIdentity
for each tenant to which the user belongs. Each of those additional identities will have their own claims for that tenant.
I am aware that claims and identities cannot be serialized in their native shape and that I’ll have to map them.
Platform: Blazor with InteractiveAuto
rendering.
dotnet 9 approach
I added the AddAuthenticationStateSerialization
/AddAuthenticationStateDeserialization
methods as per the dotnet 9 instructions.
The function that they accept requires the input of AuthenticationStateData
, which means it’s already been deserialized.
But the deserializer only works on AuthenticationStateData
. I tried deriving from it, but I can’t seem to configure a Json converter to handle it, especially since System.Json.Text
wants me to put an attribute on the parent class (AFAIK).
So that died pretty fast.
dotnet 8 approach
Back to the drawing board, I set up the Persistent/Persisting twins.
In this case the webassembly
client is getting the data properly, so I know that I am creating, serializing and deserializing all the identities just fine.
What’s not working is the server side. It looks like OnAuthenticationStateChanged
is getting called on the server multiple times and the last time through my additional identities are not there.
I thought I’d ask here because maybe I’m missing something.
My only alternative is a pretty ugly hack of AuthenticationStateData
to make it hold all the data somehow and then more ugliness on the client side to break it up.
TIA for any guidance.
Hey @nhwilly,
Honestly, I’m not sure how clear your goal is to me, and so I can’t give you an adequate answer. Do you have any code sample to share? A repo with just the relevant part of your code for this claim mapping stuff?
I created a repo. The branch you want is andrea-example
. That’s using the persisting class approach…
Almost forgot to add this: nhwilly/Auth0
The code is not pretty, I was just trying to understand how it all fit together. You can see the problem if you run it. To simulate the problem, ensure that the site cache is cleared so you can view a server session. Then refresh and you’ll see the additional identities are in the webAssembly version.
It’s possible I don’t understand how this works or there’s a problem with my approach/code.
If you look the master
branch, you can see how I hacked my way around the problem using their new methods.
The problem with the dotnet 9 supplied methods from Microsoft is that the deserializing function expects an AuthenticationStateData
type and I don’t know how to derive from that and make it work. So, I jammed my data into their structure and then parsed it out in the deserializing method. Yuk.
But at least it’s working.
That code needs to be cleaned up as well, for the record.
Hi @nhwilly,
Thank you for sharing your code. I finally found some time to go through it but, honestly, I got lost . Bear with me,
maybe it’s because I have no clear idea of your goal or just because the code is a working in progress…
Anyway, if your goal is to add custom claims to the identity of the current user, as far as I know, the following flow should work:
CustomAuthStateProvider.cs
(branch master
)Program.cs
on the server side.master
branch but not in the andrea-example
branch (not sure if I misunderstood…)AddAuthenticationStateSerialization
and AddAuthenticationStateDeserialization
.SerializationCallback
and DeserializationCallback
stuff.I’ll try to do some tests when I have some more free time.