Angular JWT User Authentication with Tailwind Login🔒

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
in this tutorial you will learn how to add JWT authentication to your angular web application [Music] hey everyone what's up this is Simon from galaxies.dev Big with a new angular tutorial and today I'm going to show you how you can easily make your angular application secure by using JWT authentication we're gonna make real requests to my dummy API and we're going to implement a login with the latest features of angular 15 which means Standalone component and functional route hack guards this will be a pretty cool example because it shows everything you need to understand about building your login and securing the inside area of your angle application as well as getting started a bit with Tailwind CSS but that part is kind of optional if you don't want to use Tailwind for the styling of your application you can use a force anything else the logic is still completely the same however we're gonna create this cool little example with a login form and registration and inside area with the navigation and behind all of that the logic to load a token to secure the pages and even to have something like an automatic login in the end if you want to check out the full source code the link below this video to galaxies.dev if it's already launched probably it's still in the early phase but very soon you're gonna get access to galaxies.dev all the tutorials all the free courses and free material and you can easily grab the code from GitHub but for now also make sure you hit the like button and stay subscribed for more videos coming in the future but now let's implement the angular application alright so let's start our user authentication example with the blank new angular application so run NG new to generate a new application I'm going to call this auth app I'm going to include a routing file and I'm going to use as CSS simply because I I kind of do this for every angular project that I start uh then we can open our editor of choice I'm as always using visual studio code and if you ask me about the color theme it's still the shades of purple and I zoom in four times you want to know everything about it all right um in our new pro day we have install a few dependencies so this is required if you want to use Tailwind CSS so to the development dependencies we install Tailwind CSS post CSS and auto prefixer and additionally I know that we're gonna need the forms package as well so we're going to install Tailwind CSS forms as well uh finally we need to initialize Tailwind which we can do with npx Tailwind CSS init npx simply runs a local script you can also install Tailwind globally but not really necessary two then finally configure our Tailwind configuration just bring up the Tailwind config and let's replace this by adding our content that should be skin and the plugins which is the Tailwinds forms um simply because we're going to have our login form pretty soon to wrap up the Tailwind implementation we're actually rushing through this but it's not really interesting uh we're gonna open the style CSS and simply add a tail and base component and utilities and then Tailwind is already done and we can confirm this by running NG surf you can also add Dash o um let me close this uh to automatically open the browser once this is done so here we go here is our auth app uh looks pretty standard because this is the default here so let's change this and we're going to change this by adding our own routes first of all or little let's say our own components so we can generate new components I feel like are we right here let me check this out are we at the four zoom level because I always do zoom four yeah we are okay okay NG generate or G component or C so you could really make this NGC if you wanted to um uh and then I'm gonna pass dash dash stand alone as well because we're gonna use the latest and greatest features of angular in this one with Standalone components so I'm going to put this under Pages log in and I'm going to immediately add a second one that I'm gonna call dashboard so we're gonna have the login page um this will generate the two hearables here we're gonna have the login page and then we can navigate to the dashboard page um that is the whole idea I'm going to make this with a real kind of real API in JWT authentication and storing the tones loading the tones uh registering users everything okay uh once we get this we can touch our routing which is in the app routing module because we generated this in the beginning so let's set up our routes um we can actually we can Define this usually we can Define it like this right and then come up with the new array and first entry I'm going to use the blank first entry immediately wrong uh in fact this is not you can use route I think this is what I used before so then it should say path do it I get code completion yes better that's better okay for the blank path what I want to use is load my components I'm not passing the actual component I'm now lazy loading my component um where do we go no not like that let's use the default load component and we can use the syntax import our page so the URL the link is the path come on it's not the link it's lock in lock-in component and since this is an asynchronous import we use then you could probably also use a weight in here right uh yeah but that I feel like the line would look horrible let's stick to this um then we got the module here and we can just call it like this so this is the new way of doing it you don't need any kind of uh module for this because if we check out the login component we're gonna see Standalone true so with angular 15 I think we're using 15 right uh yeah with angular 15 uh we still need to use it like this I don't know if this is going to change it like angular 18 so if you come back at this tutorial in the future it might have changed however um we don't need to create any kind of modules for these pages and we can just add them like this we can do the same now for dashboard and then we will have the dashboard component right here I'm going to call that pad of course dashboard so for now we have our two routes defined and to display the actual uh information we're going to get into the app component because this is the page that is currently displayed so what you see here is inside the app component with a lot of styling um and a bunch of HTML and what we're going to do now is we're going to select everything and remove it and replace it with router Outlet so that simply means we want to render as the first thing our angle our router and the angular router will take care of displaying the right pages so now we got login works because this is the first entry that we display here even now navigate to slash dashboard we're going to see that dashboard works so we have our general navigation kind of figured out we just need to implement it um so let's take care of the login and probably we're going to do this side by side um to get a good feeling let's open this and then and to build the login we're going to use a reactive form and if you have used director form before you know that you need to import direct forms module and because this is a standalone component we got our Imports right in here and don't need to touch any other file which is pretty cool right so let's add a simple form in here uh for which we're going to use the form Builder so let's inject this private form Builder form Builder and then we should also add the validators from angular forms cool the starting point we can actually also add two functions so if we submit a form we can actually handle the both the submit and the creation of an account on this page usually you will have a registration page for that but I'm just going to stick it to this so now it's time for the UI and with Tailwind that means we're gonna have a bunch of fun so I'm gonna bring in a few classes here and there simply because they just sew along um but we can start by surrounding our stuff and positioning it in the center uh also using justify Center I actually got I think a Tailwind um oops a Tailwind extension here that brings up those classes so you're gonna find them under extensions here just search for Tailwind yeah they'll win yeah that's the only one I have installed Tailwinds CSS until it sends pretty nice one okay and we'll get rid of that again and let's close it um I put in tests so that should already Center our stuff um in the documentation they had just like a little image up there I'm gonna take my image from the Galaxy's Twitter profile I'm gonna remove the test in here so then we have it like this you probably also want to have a bit more uh space to the top so let's add a class uh using the full with I don't know sometimes it's not working with the intellisense sometimes it is and sometimes not strange um maximum so this is only important later maximum width and then a bit of space this is kind of important because that will give our page some more space okay um this is just the image what we need as well is a form now and we need uh buttons so this is the starting point of our page on top of that maybe we're going to add a bit of padding padding wine 12 so then we have it a bit more down and we probably also want to have X petting but we yeah let's let's wait for this let's see that actually scales quite nicely it's in the center so that should be fine for now okay uh for our form um let me bring this in so here we go uh the form looks like this a bit of margin and a space and on submit we're gonna call our submit function because we're using a reactive form we connected through the form group to our form variable that we defined in here and then we can just attach the email and the password to the right input fields so uh it would get started we can now just have simple input field like this for the email looks not too good I'm gonna probably change this a bit um however we got our label for the email uh for screen readers and we have connected our input form using form control name the rest is really uh not related to angular but this is part is related to England this is more related to General HTML required autocomplete email so it will put in the user email and then we got a long class uh that you can check out on the written tutorial on Galaxy's dot def of course on top of that we also need a second entry which is just the password field so you can have it really just like this if you wanted to in fact you don't really need anything else actually it looks already good for default login you could pretty much get started with that however in my previous setup I had an additional class here uh with a little Shadow around all of this so let's wrap both of these in this new div and do we get the shadow yeah I think it has a shadow uh let's let's use LG yeah then it has quite a big shadow uh you probably don't want a shadow that big so that's why we have the small Shadow uh it's it's Sceptile it's subtile okay looks good now we just need the buttons to submit this um and we're gonna give this or make this simple Flex layout with a gap between the items so now we could have like a lock in and then we can have register and oh oops I think we're on the wrong div here um am I still oh I still should be here yeah then we are at least here um however uh those are next to you do we want to have them next to each other yeah probably why not why not we can keep them next to each other so uh for the first button I'm gonna replace diff and instead we're going to use a button um we're gonna call this one create account and this will now take up most of the space but if we come up with an equal button for our second reel let's just copy this one uh we're gonna see that those two gonna share the space if we don't have anything else Flex will just align this equally um you could set this up to if the one bigger or in general you could have them below each other if you wanted to do that we would use flex uh row no I always mess this up then it's flat it's called so if I add them all that in a column they would be below each other by default we're using Flex row so they're next to each other and share the space of that row and the Gap is this tiny little space you see in between uh so if I remove that that uh they would kind of stick together okay anyway we're not too much uh this is not a complete Tailwind tutorial so I copied this button styling really just from the Tailwind uh UI page the first button will be disabled while our form is invalid and on click we're gonna call create account this is important because usually the form has an NG submit set to unsubmit so if you have any kind of button within the form it will usually trigger this on submit and we do gonna use this on the second buttons I'm going to set this type to submit however if you set the type to button even within a form it's not gonna triggering the submit function and you can just attach your own click Handler that also means for this button which I'm going to call sign in um we will have the type submit okay and that is fine now if you also want to have like an SVG I copied this as well um simply from the hero icon so those are pretty nice icons you can use with tailwind and I always give you the SVG so on top of our create account or in front of create account I'm going to put this little icon here uh can we give this a bit more space because this is interesting you can use the valid um how do you call this keyword uh filter uh I'm gonna have to look up the exact term however by doing this you can specify how that button behaves if the form is actually valid so right now the form is invalid did I save this yeah I think uh so now I get a pointer out here and then we get this effect if it's invalid I get no more pointer and nothing happens so this hover effect only happens if the button is valid and we're going to add the same kind of thing to our sign in button so again and then we got two nice little buttons here okay um let's try a simple example can we lock this out and let's open the dev tools on create account it says create email and password and on sign in it doesn't say anything um that's good point let's see uh type button type submit it's disabled when the form is invalid and this button is interesting are we still inside the form I don't think we are right so those buttons I think they should be within the form where's the end of this this is the end this is the end you know okay let's put it into the form because if the button with the submit is outside of the form actually kind of doesn't make sense yep now we got this right so create calls create sign in calls submit and we have our general setup for this page it is responsive it kinda worked low come on if the page is too small um yeah we could probably set up something for that um let's see if this page is really small we should give it some some kind of heading uh let's say for small um devices we're gonna give six and for large uh we're gonna give a padding X of eight so then we should at least no oh sorry I didn't mean to move that one um oh no I don't give anything okay so let's say in general yeah now we do have something on all platforms now we have four here uh we could probably break this as well so if we wanted to do that uh we could change this and say by default we're using Flex call and starting at I don't know MD or SM we're gonna probably SM uh we're gonna line them next hello oh did I mess it up again no okay so we got them column aligned and then we got this uh I think there's actually another breakpoint I think it's XS right or no what's it called is it s uh is there any other Tailwind CSS break point and A1C is is can I search yeah break points um the smallest yeah that's the smallest one okay you could of course change the breakpoints however uh I think this should be fine so we got this uh by default we got this setup if we get too close uh too small we still have padding and it should work on every platform and we got create and submit working great uh that means we can keep uh on doing the real work which is actually creating a little uh service so let's generate a service because in that service we're going to make all the API calls and perform um the logic to handle our JWT stuff so NG generate a service I'm gonna just call this authentication and take a sip of coffee oh you know it's it's just 9am when I record this right now and I just had like a few sips of coffee please bear with me um but anyway I think I'm doing good for just a bit of coffee at 9am not too bad not too bad okay [Music] nervous oh altercation server sir we want another package I just remember um we're gonna install the jwtd code package let's see if I can move this up uh David tease it on GitHub somewhere yeah JWT decode a super simple package this layer doesn't validate the token any well-formed detail can be decoded yeah it's just for uh it's really just a super small library for decoding if you want to validate a token you probably want to use another library with typescript is really just calling jwtd code and it's as easy as that so um how when do we get started um probably by creating register functionality so let's inject the HTTP client oh if we inject the HTTP client here in the authentication cells we should also add it to the app module so let's add the HTTP client module I still don't have a snippet for this um I don't know this is like the only import that's not working automatically for me and Angola common slash http and make sure you got that array right okay we got it now I can also edit in here thank you and then we can create our functions so the register function and the login function uh log in with email gonna be a string password gonna be a string or an S string okay and then we gonna return this dot http then I call this HTTP client oh that was not my intention always call this HTTP uh this dot HTTP login is a post request to my very own API at developaterapps.com so I purchased that domain uh some time ago there should be an API documentation somewhere here's the Swagger you are nice I designed this nicely um there are a few endpoints we can use uh and authentication is the endpoint to get a login so we're going to grab this can I just give the URL please give URL uh okay we got this so api.developaterapps.com auth and then email and password okay please make this a few lines so people can also read it perfect so this should give us back some back some kind of information and we're going to add a little pipelock here because we want to transform the output so we get back any kind of result um no we don't need brackets here but here um so I'm gonna just return it again um hello what's the problem yes at the import please oh come on why are you mad with me um not enough brackets I feel yeah that looks better so we got this login function uh how can we trigger this well we can just hook this up to our page and probably well let's just start with this so this should be called here I'm gonna grab the email and the password from they start form get raw value so because I'm by the way defining the form up here since angular I think 14 now it doesn't matter anyway we can have strongly typed forms so then the form actually knows that it has an email and password and that's also why this works because get raw value knows that it will return an email and password okay and then we can add our authentication Service private auth um service this no I was too uh fast uh they start off service login I'm gonna send email and password over and then something is gonna happen so we're gonna subscribe here I'm not gonna handle the result or anything right now just like this because then we should finally be able to actually test this so this is like I think my test account yes submit and we do get back an expiry time and a total so it's a really super simple API there's not a lot connected to this [Music] but it shows one thing and that is we have managed already to build the UI the form the logic and the service and now we just need to piece together a few more things and then finally of course secure our application because that was the general idea here now we could keep track of that token pretty easily in memory with just a value however we also most likely want to load the user when the page loads because you don't want to authenticate your users all the time again so in the Constructor I will very likely call not the title strategy whatever it is but this dot load user which will load a token from Storage so let's first of all Define a little storage key here so we don't have to type that string again um however I feel like in some situations this is going to be in a synchronous operation either because you're probably using something like ionic where you're actually making an asynchronous call to get something from the storage or you might want to validate something and in general I feel like it's more secure if we Define our token distort local value on a behavior subject where we can just emit new values once we get them and then just react to the changes instead of having um just a static value and then probably some race conditions if we later introduce the guards to protect the pages so therefore let's add a private user which is of the type Behavior subject and then um oh let's add a little little interface so we're going to Define that a user data could look like this so we'll have a token and an ID of the user the ID comes simply from decoding that tool so the the behavior subject will either have user data or null or undefined and that's very important because I'm going to initialize it with undefined new Behavior subject undefined now why do I do this um we're gonna see later um yeah it's not red we're going to later see that I'm gonna filter this initial value out which is like the placeholder for the loading state so undefined simply means we're not yet sure it's like the schroding as kit so maybe user is authenticated maybe not we don't know at that point we need to look into the box so let's look in the box um on log in we now want to store that token so we will be able to retrieve it uh next time I'm going to do this in our map block here in fact yeah we're gonna yeah we're gonna slightly change the result we could also use a tip block um doesn't really matter too much okay let's start with local storage set item we're gonna set it to our user storage key and we're gonna set the tone because we've seen uh tokens here in the response under response dot token so this will first of all store the tone then we're gonna decode it I'm using JWT D code oh you can't import that automatically come on JWT decode import it's just 1.4 kilobytes really compared to everything else we're using that's just a little just a joke uh so decode our token please and then I'm going to add a little block here so we're gonna lock this out as well once we get the decode total we can actually create a new user data object so we can also use user data and that's gonna look like this totem uh our totem oh but um um what will this return by the way um interesting uh nothing real so we're going to use the token and for the ID we're going to use decoded Dot I think we only the only thing we get back at decoded I don't get back anything here is of the type yeah you can add for the for the totem you could add a certain um type of the total instead of JWT payload let's try JWT payload is it really I don't know um oh yeah I should probably then remove this line of any yeah uh well nah it's not everything included I think uh at least I think so but the sub should be included let's try it first of all so on login uh we should probably lock the decoder say what's your problem it's not assignable uh um private user data null undefined do I have to repeat that line okay a problem typescript so unlock in we say submit we see result and this is okay I get my IAT and a sub I could even include that as well if I wanted to but I know that the sub is really just the user ID in the in the system of my dummy API um we could also keep track of the expiry time but we really want to focus on the protection of our Pages um pretty soon so let's keep it at this now the important part is to say this third user next with our new information and then it doesn't actually matter too much what we return here um for our view because the login will just yeah just go to the to the inside area after we are done with this now the red they're actually pretty easy we do the same call to our API just to register and after the registration is done I'm going to use a switch map block because with switchmap I can switch to a new observable and what I want to do is I just pass the information that will pass the register to login and then perform the login because I don't know if you don't have any kind of email confirmation you can just directly log in the user at that point which I don't have in this system now the only thing is that at this point we're not let yet loading our information so let's do this uh we can load our token in the user function by grabbing it from local storage if we do have a totem uh we're gonna decode it just like we did before okay grab that line um I'm gonna actually grab everything from here right only thing is I'm just going to decode the total um the total in this case is yes the total so just keeping it in memory in case we needed to like include in headers of future calls I'm going to emit the new user data and in the case we haven't found a token so here in the else case I'm also going to call this but with null so that means we have skipped the undefined phase um and now if anyone checks we have a certain value so we can always filter out this undefined State because this simply means our app is not yet initialized and this is going to be really important for our logic in the end um to protect the pages now just three more functions that we're going to add just a little helper functions so we're going to have a sign out which removes our token and sets the big user back to null a helper function to get the current user so we get it as an observable of our Behavior subject because the user is private nobody from the outside of this service can change it and we just get back the observable that's a secure pattern and then we also have a function to get the current user ID well it's not super secure if the user is null you shouldn't probably call it but I know I'm just going to call it when the user is set so that should be fine for today okay let's hook up all of this to our functions so for the login I'm gonna change this a tiny bit uh usually I would have something like the value here and then the function however if I want to implement um this in the new kind of way and what actually pass in an object with next and error um it's like the cool kids doing the stuff so next um in that case I'm gonna do just let's just put a lock lock in done and then I'm gonna route forward to the inside area so let's inject the private router here which is the angular router um maybe making this a bit bigger and then just calling this dot router navigate by URL navigate by URL and I'm gonna go to the dashboard page in the error case well you can add some kind of like toast message or error or whatever I'm just gonna look the era for now um or we could yeah we could set it to all local errors so this dot error equals uh login field set smiley yeah I said because I can't even spell this correctly okay um oncreate is pretty much the same now I'm going to remove that and we're going to call register um yeah register the login for us as well uh so I'm going to call register done it will do the same but the error will be registration failed now we just need to find a place where we connect our error to the HTML um why do we just play this I don't know below the buttons just in case something goes wrong I don't know where I added this before I think yeah below the buttons something like that uh are We Done Yet I feel like we're done let's try I'm gonna actually create a new account let's call this B add B dot whatever I'm gonna call create account this creates the account we get back a result register done and we're on the dashboard great good news everyone can we confirm that on reload we got a token we can so let's try okay we're not injecting our function so it's not even loading the user yet and but if we go to the dashboard we can quickly fix this let's inject here in the Constructor the private uh auth service we anyway need it in here for the lockout so if we got it in here we go it should load and we get back a tone when we load the page that is good news because this will be very helpful for restoring the user session so we don't have sessions we just have the JWT however it kind of acts like the the session okay uh let's wrap up the dashboard page real quickly now because then we can add our final functionality so what we need on this page is the angular router so we can call our sign out and route back to the login and I'm also going to grabbing the user ID simply to display something on the dashboard now uh We're Not Gonna display uh We're not gonna build out the dashboard page with Tailwind together today because we're already I guess at how long is this video I don't know oh it's almost already almost close to 40 minutes yeah so let's just add a header bar now uh I took this from the Tailwind UI page I think so it's a very common pattern we got the login and we're on the dashboard can't actually go anywhere else but you could use this as the base for your application if you wanted to and then you would have some kind of main area below the header uh we can display some kind of content actually pretty nice pretty easy to set up um the only thing you might want to do is have some kind of inside module where you define the routing so then here you would just Define this main area and then put in another router outlet and then let that router Outlet be replaced by the actual routes so you don't have to set up everything at the top level however that is just a small thing we're able to log out um if we now reload the page we're also going to see that the token from Storage is null however now the problem comes I am of course still able to go to that dashboard page um okay the dashboard page encounters a problem huh because get current user ID yeah we should probably be careful with that we should probably add a question mark here then it would work right yeah then I'm able to get to the dashboard even without a toe so we will now want to prevent xs2 pages with a certain functionality and in the past you would have used a guard for that and we actually kinda still use a guard for that but we can actually make this functional um so let's go back to the app routing and what we're going to do is we want to add a function here called can activate and you can activate we previously had like an array uh with um like the guard you can generate a guard using NG do you have something here yeah just like this NG generate guard and then I would create a guard file here it's kind of yeah complicated to set up but its additional file to manage and a bit of typing so instead of doing this with a guard we can now also do it within the service but by the way guard is totally fine and if you check out one of my other videos you're probably gonna see that I'm I've used a guard in the past um but we can also add simply a new function to our authentication Service um and within that function I'm going to inject directly the router the angular router so I don't have to add this to the Constructor actually um and we could do this really this part we could also do it right in here but it looks kind of ugly what I'm going to do now is I'm going to return the current user observable and I'm filtering out undefined I'm filtering out undefined because as said before this is the state where the application is not even initialized so we don't know if there is a user or not so we filter this value out and this observable will only return once we get either a value of user data or null and if we got a user like if we get any kind of object back we're going to return true which means the user is logged in and in other way other case we actually return an URL tree which simply means we change our routing exactly to just slash we can also return false and then handle the routing but this kind of works better now with that in place let's go back to the upper routing and in here we now do the fancy stuff uh functional guard using inject again we directly inject our authentication Service in here with this approach um and then call is logged in so this is our new guard and once we apply this we should see that we are not able anymore to go to slash dashboard and to that page definitely not because it doesn't exist and we're brought back to the login because we have no tone let's try and sign in okay I'm signed in I'm here let's try refresh and I still got access because I was able to load this tone from Storage again let's try refresh Works log out nope no more access to dashboard and that is how you can protect access to pages with a functional guard using angular 15. now on top of that I want to show you one more thing because what do you see in a lot of applications is if you are logged in and you go to the login page you're actually brought into the inside Area automatically so we can use pretty much the same setup here and just add another function uh which I'm going to call should log in using same setup filtering out the undefined state but if we're authenticated we're actually going to do uh the opposite we're gonna create a URL tree with the inside Area the link to the dashboard and if we are not authenticated we return true because we allow access to the login page and now with that in place back to this copy this um add this up here and change it to should log in as a result we are logged in and if I try to navigate to the login I'm actually always brought back to the inside area so this actually can sometimes be a bit annoying on some pages where you really want to get to the like the whatever kind of page however in most cases I feel like this is pretty nice if I just want to work in the inside Area I don't want to do the login all the time again and also I can refresh on this page it won't bring me to the inside page unless I'm signed in so dashboard page protected registration and sign in working and refreshing that page also worked because we're loading the totem from local storage and that's my friend is everything for today's lesson on JWT authentication with angular all right and that's it for today's tutorial I hope you enjoyed this quick example of building an angular login with tailwind and jwts and one last point is that it's not a hundred percent way to make your application secure real security always happens at the API level so you need to make sure your API endpoints are protected there's no access to the database behind this without being authenticated and all that stuff everything we've done with angular is just like the front end stuff yes we always do this but just keep in mind real security happens at your back end if you enjoyed it please make sure you follow galaxies.dev and of course subscribe to this channel for more videos in the future and I will hopefully catch you soon so until then Happy coding Simon [Music]
Info
Channel: Simon Grimm
Views: 3,603
Rating: undefined out of 5
Keywords: angular, hybrid app, javascript, web development, angular tutorial, jwt authentication, typescript, angular tutorial for beginners, learn angular, angular course, angular crash course, angularjs, angular vs react, programming, angular 15, api, crud, angular project, angular 14 tutorial, angular material, route hack gaurd, hack protector, hacks, malware defence, login security system
Id: Fe5K58Elf6Y
Channel Id: undefined
Length: 45min 31sec (2731 seconds)
Published: Tue Mar 21 2023
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.