Bearer Token Authentication with Blazor WASM in C# .NET 8

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
and last video I implemented Bearer token authentication using the.net 8 identity endpoints into my end-to-end authentication module now I'll continue with that Bearer token authentication in Blazer webassembly I'll start by making sure that on a page refresh the user is still authenticated so that returning page visitors don't have to manually log in each web app visit after that I will present you with two approaches to Blazer webassembly authentication the first approach will be the one that Blazer provides out of the box the second approach will be the keep it simple stupid approach and I'll make sure to publish both approaches to my patreon so you can choose either one so we have everything to make this work once authenticated in the local storage will find our access tokens and refresh token so that's all we need so now to let's say I refresh on refresh I should get those tokens from the local storage and try to get the user info so by calling that alt manage info endpoint if this was successful we know our token is still valid and we have our current user so we are authenticated with the backend which means we can be we can tell our front end that we are authenticated if it wasn't successful that could be because our token is invalid or expired if it's expired we could refresh the token first if that was successful refreshing the token will get a new access token which we can then use to retry getting that current user and then we know we're successfully authenticated with the back end so we're safe to set dull or fronted that we are successfully authenticated if that fails we're not going to try anymore so then it's up to the user to read re-authenticate manually with our web app so in the meantime I made this work if I now refresh the user gets automatically logged in that's where you see that test gmail.com refresh and you see the test gmail.com and in here you see the network call got made and we get a proper response so let's now dive into the code so this odd State layout is now a component you could place anywhere on the page either on the main layout or on an individual page so all it does is initialize the authentication state let's take a look at that so and it's all tokens that's where we start with if this is empty we're going to get those tokens from the local storage there still are none or or we are already authenticated when the current user is already filled in just not going to continue that means we have everything we need set the authentication HTTP header so if we correctly set these all tokens we can then authenticate our HTTP client so setting that HTTP client header to then initialize the current user if we don't have it already tries to get the user info if it was successful perfect then we just set another property in the state and we just exit the function so let's have a look at the state so I just added two so all tokens and current user which this one holds the tokens of course the login response access token refresh token and this one holds the email email confirmed and the claims let's say it wasn't successful because the token expired or it's just invalid tokens or something then I'm logging something could not get current user attempting to refresh the tokens now so that's actually what we'll we'll do next is to use whatever tokens we have and try to get new ones so refresh tokens which will post to our endpoint with that stored refresh token from the local storage if that for for some reason failed that might be the reason that the refresh token is invalid or yeah expired or whatever scenario and in that case we actually want to clear everything so unset odd States so remove the current tokens from the local storage since they're probably corrupted or expired or invalid in any way uh we set all this we clean out the state and we unauthorize the HTTP client if we were successful we're going to set those tokens into the local storage and authenticate our HTTP client then after they refresh string of the tokens was successful then we try again to get that user info so we're basically just trying two times okay this so that was all the code to make sure a user re-authenticates on page refresh um but we still have a major problem and that is only the authenticate the odd State layout component now knows about this authentication state all the rest of our application doesn't know anything about our authentication state so for that we could use the Microsoft official documentation Pages for client-side Blazer Authentication so that's the first approach so we start by this using this Builder authentication I'm going to add that to the extensions method underneath here and then you'll see my server side project to my pre-render server isn't complaining about adding the authorization middleware so I'm gonna do that which is a bit unfortunate uh it should be a project that can plug and play Standalone modules so now I'm adding things to my module and then I'm adding things to my implementation project which makes that I can't let's say I start a new project and I add in that authentication module it's gonna error because it doesn't have this line and then I have to do something else I have to add the cascading stuff in here let's see components dot observe characterization from Microsoft newest 2D implementation projects because we're working in this app.rezer and then we need to make sure the authorization is there and the Imports as well authorization to have these cascading authentication state and then we could all add that authorization route View that you see here so let's add that instead of the route View I think okay and then at once that authentication State provider for that costcading thing so I'm gonna add that to the shared Spa of the auto module and that one inherits from authentication state uh yeah we need a nuget package here as well or maybe only here since the implementation project implements this one so let's add that and I should be able to inherit from that Implement missing members which will be the get authentication state async how to make this work yeah to get rid of that error I think I'll have to say Services dot get scoped that should resolve the issue and of course we don't want to throw location state new claims principle yeah just like that that would tell our application that we're unauthorized yeah because there is no claims in there so let's now try this authorized view as well as the cascading out State parameter and I'm gonna copy over all of this as well let's see and I'm gonna put the odd message underneath let's see what that gives okay I moved it down below just to see it's better so this is the you're not authorized from the not authorized View and the odd message is not visible so yeah that was as I expected because this boilerplate coat does not know that we're authorized it doesn't even know that we have the bearer token at this time so we'll have to tell the authentication State provider that we have that info so this is what it would look like and the custom authentication State provider you initialize these this identity this principle forming that user object and pass that along as a new authentication state we're gonna pass that along to and that's where it gets interesting to an event so it's likely that the cascading component that you saw on the app.rezer so this one it's likely that this one listens to listens to this event so if we take a look at that this invokes authentication state in changed which is an event which will then make sure that from the top down that authentic authentication state is passed as a cascading value which then makes that I can access it on the user info page so this one will then be updated as well so that's pretty interesting that event getting trigger invoked to notify we are the necessary components that that authentication State changed but now we first need to find a way to get our Bearer token the the claims in this object because only then we have successfully told the our application that we are authenticated so that code would look as follows a custom authenticate method that now the claims identity is set to the current user's claims but that's a dictionary so we have to reformat that to a new to an innumerable of claims so and now we should you have a valid authentication state okay I had to look at another example of a custom authentication State provider for Blazer server asp.net core 7. what you see in here is so they also have the custom method but they added the yeah just a string with something in there which apparently makes a difference and then the injected authentication State provider as it is so not the custom one the actual one but then they cast it to the custom one to access that authenticate e-user okay so I kind of did the same authentication State provider injected on my old State layout Custard with custom State provider and then called it authenticate and passing along the current user data holding those claims and add that random string and then you see hello test gmail.com which comes from this and another cool thing you could do is the attribute on the page and you can even pass down roles like admin and I think you separate them by comma you can also specify the rows on one of these to rules and the message you saw top level not authorized comes from here I added this not authorized component inside of the authorized route View if you like that approach I recommend you use this official documentation page of Microsoft I'm not going to continue with this approach I'll be using my own approach since I find this a bit much for stuff we already have and already know it might not seem like much but wasted hours making everything work I have had countless Eric Pages for some kind of middleware or not properly registered services and I don't like the fact that I had to register services in multiple different places after all of this setup we still actually need to tell the application that we are authenticated by simply passing our claims but make sure to let me know what you think about this official Blazer authentication approach there are definitely some interesting Parts about it so the time has come for the alternative approach and there will definitely be similarities I'm going to start with adding an event on outstate change which I then want to invoke which is similar as the notify odd State change so let's call this notify what state changed and I'm going to have to call this for it yeah let's make it public so I can access it in the HTTP client I'm going to have to call this after the authentication State changed so let's try State provider notify how to say changed and also after logging in manually so let's have a look Logan let's see notify notify would stay changed and then after refreshing oh here unset alt State I also want to notify that I'm no longer authenticated and I now want my odd State layout to listen to that event so whenever I initialize this component I want to start listening to that on odd State change event and whenever there's a change this method will be executed and when I dispose of the component I want to stop listening to that event but this of course will be called whenever the user is logged in or even when the user is logged out so at this point we're not sure which one of it is and if you remember from the previous approach the way we told our application that we were authenticated was by making that claims principle and the odd state by actually just passing the current user's information and claims so we're going to do a similar thing but just with the current user's information if that is not null we assume we're authenticated correctly if it is null we assume we're not authenticated so I'm going to add a state property of maybe I'm gonna do it above is logged in and we're simply going to set that to whether the current user Dot email this email a good thing yeah you could even try the claims is not null or white space and remember when we insert the Old State we actually clear out all of these values so that's a good thing So based on that property that the value you could add some redirection logic with the navigation manager let's say you want everyone that access a certain page with this component to be authenticated if the user is not you might want to redirect them to the login page or another page of your choosing or you could even do the opposite and when a user is authenticated you could lead them to the admin section of your website let me just leave that optional so now this odd State layout component will know whenever we're logged in or logged out and will also know it whenever that changes while using the app but how are we now going to tell other components that we are authenticated or not we could use an event callback or even a render fragment let's start with the event callback and explore the possibilities of that I simply added a parameter the event callback I pass along the bull which is going to be is looked in the value of that and then the event callback which I'm going to then invoke down below and hook a sync a person State provider dot is logged in now I can go to the user info page the hot layouts and use that event callback on odd State changed and then do something whenever that odd State changed let's see if we can directly have the is logged in and I simply pass along a method to lock this whether we're authenticate it or not and I changed this console.writeline.od state layout plus is logged in gotta clean that up a bit and let's see if that works and running that gives this alternate layout true and user input page true but note we're still not seeing any changes on this page so still did not authenticate it and still we're not seeing the user info or the claims and that's because yeah this user info layout is not being re-rendered the responsibility of this odd State layout is simply to tell us whether we're authenticated or not we're not going to add any logic in here to say if we are logged in do this and that or that we could yeah like I mentioned before we could add in the redirect logic but let's make some other components for actually adding conditional statements depending on that Authentication so I simply made another component authorized layout the stone which uses this odd State layout and has uses the event callback as well and I customized the console.red line to tell me that we're also I am going to add a property has access and I'm going to add an if statement has access and then I need only when access was approved I want to show the child's content I'm going to add another property parameter required policy which is basically going to allow the implementer to pass a method that is not yet invoked and we can invoke it in here and a method that should return a Boolean so for example has administrator access so I'm going to set that property as access based on the acquired policy if it's null it means we don't require any extra roles or permissions but if we if there was a policy passed along then I invoke it so this could be has administrator access then that gets invoked and that will check whether that user has actually has admin access but let's not worry about this required policy yet again here you could add optional logic that says this would be a navigation manager if you inject it and then you could say navigate away or whatever so if you don't have access you could redirect out of there and otherwise you'll see this H2 no access so either you get redirected out or you the content gets replaced by no access and we could pass along that event callback simply to re-render when we need to so that would look as follows and then I make this async task and I'm simply adding a console log statement just for debugging purposes and now let's go to the user info page and actually try it by doing authorized layout and adding that in there so if we take a look at the demo if I refresh I saw the no access and then suddenly the we have access perfect and now for this required policy I made a simple function just as an example as admin access let's just set the two false for now and then we see the no access because of that if statement or we could have been redirected out of this page because we might not want an unauthorized user to be even on the speech of course instead of that dummy return true or false we'd actually want to maybe check whether the user has certain roles or certain permissions or certain claims but I will keep that for a future video of course we don't necessarily have to wrap the user layout we could wrap the whole page if we wanted to like that that is just fine as well and we don't actually need both the odd State layout and the authorized layout since this authorized layout already calls that Old State layout so without this required policy this component only checks whether the user is logged in with a required policy it could do an additional check on a requirement so this component can actually serve as the authorized view unauthorized view from out of the box Blazer but it all can also serve as the attribute on the page if we if you rather make an attribute you could probably make a custom attribute similarly as this component and if you'd want an authorized view you could you I think you have enough yeah to do that as well I could probably make this component better oop do it like that I can add this tag now authorized content and that works and then I could actually add an authorized content and say just like that that would be useful if you don't redirect the user out and you want to have something else then the the new access and why I actually just did that is because I want this log out button at the top so in my odd nav menu I can then do the authorize layout and then when I'm authorized then I display the logout layout and otherwise I display the login and register buttons I moved it to a separate component because that's calling that internal HTTP client and I made a logout of method which basically just inserts the odd state it actually doesn't really make sense to have these methods on the HTTP client although this alt header but also these local storage ones maybe I should move those to the state I introduced some books I'm sorry for the people who were typing along so this and operator change changes to an or method I forgot to or this disappeared to store the authentication tokens and I improved The Code by now so that will be available on patreon and also in here an important one is looked in had to be checked of course included in the check because otherwise an authenticated people could have had access the improved project will be available on patreon so I'm going to continue with this approach since this is for me a lot simpler and it's contained to this authentication module which is a requirement for my project I don't need to have code all over my project for this to work it's a bit Reinventing the wheel but in a much simpler way maybe a bit less flexible by that I mean this might fit all my requirements all my needs I have tested this on multiple of my own applications and that's sufficient for me for someone else maybe that's not enough maybe it needs to be more like the out of the box Blazer way I have already made a video about authentication and Blazer web assembly and this with this approach and in that video I go more in depth about those role-based authorization functionality with that required policy so I'll leave a link down below so you can watch that if you're interested let me know what you think about the out of the box Blazer approach and then you may also let me know what you think about my Approach I'll make sure to publish both approaches to my patreon so don't forget to check that on the next video I'll go more in depth into authorization but this time it won't be role-based authorization so make sure to subscribe to stay tuned and if this video was valuable hit that like button and I hope I see you in the next one
Info
Channel: Keep it simple, stupid.
Views: 5,672
Rating: undefined out of 5
Keywords: web, app, development, dotnet, pwa, ml, ai, frontend, backend, cloud, azure, fullstack, .NET, C#, machine learning, artificial intelligence
Id: 7kyIEnQ8kF4
Channel Id: undefined
Length: 33min 19sec (1999 seconds)
Published: Tue Sep 26 2023
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.