SvelteKit Authentication Using Cookies

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hey friends today I'm going to show you authentication in cell kit using cookies so let's not waste time and let's get started if you want to follow along I'm using a regular cycle project with typescript you can set up with npm create swelt and you can find the project files on GitHub to set up the database I'm going to use Prisma because you can just write a schema to define the tables instead of writing raw SQL which is awesome because I have no idea how to write this skill I'm using sqlite for the database because it doesn't require any setup since the database is just a regular file on your system so let's get started you can open the terminal and this setup couldn't be easier I'm going to open this terminal and let me just open the sidebar so you see what's happening so in my case I'm going to use pnpm but if you're using npm it's just the same so I'm going to say Prisma init data source provider sqlite and a couple of things are going to happen just give it a second so it's going to create a Prisma folder with the schema Prisma which is awesome and then it's going to create the enu file and it's going to populate with the connection string another awesome thing about Prisma is that we're using sqlite but later when you change to mySQL or postgresql you can just change the connection string and you don't have to change anything else so Prisma is really amazing but yeah I'm going to close the terminal for now and these files are going to keep the Prisma file open and close the sidebar and then let's just create the schema for the database since this isn't a Prisma tutorial I'm trying to do my best to explain things but yeah let's get started so here is just the setup for Prisma you can ignore this this really isn't important so let's create the tables and this is called models in Prisma but it's really the same thing so for example we can say model user and then we're going to give it an ID and if you're wondering to get formatting I'm using the Prisma extension in vs go so you can get that if you want and I'm going to say that it's of type string it's ID and it's going to be default and we're going to assign it a unique identifier and then we're going to have a username which is also going to be a string it's going to be unique and this is the most important part so we're going to have a password hash because storing plain text password is the worst even if your database gets compromised the attacker would need to decrypt the hash right and then we're going to have a user of token that we're going to use for the session ID when we create the cookie and we're going to create a new one each time the user logs in to be secure in case it gets compromised so you can also say unique there are some optional Fields created at daytime is the built-in type so you can say default now so we're going to give it a timestamp and also update that date time we can say updated ad and this is the interesting part so we can just create another table model so we can give it an ID this time I'm going to use an INT and we're going to give it default Auto increment so it's going to be one two three four Etc the roll is going to have a name and you're going to create the roles going to be unique and now we just need to connect it to the user table so again Prisma makes this super easy and then we can go here we can say roll I'm going to refer to the table and we can specify our relation so it's going to use role ID which is going to reference ID let me just do it like this you can remove semicolon here we can do it like this and then we can add role ID and that's basically it for the schema but another thing I want to mention is that later when you change to mySQL or postgresql database you'll need to change the connection string and don't have to change your schema but you can also use other features only those database support like enums for the user role and if you use any of those other databases this is even easier to create roles let me just show you if I open here the Prisma documentation give it a second and you can see how simple this is when you use enums in a supported database you can just create enum roll and then you can say user admin and this is the only thing you have to do which is way easier but I really don't want you to struggle to set up a database Etc and want to make it more accessible so you just keep this in mind you can do that later if you want but yeah let's continue another thing I want to mention for the schema is that you could create a separate table for the password to reduce the risk of querying it on accident and sending it to the front end this is just a security precaution if you want but you really have to do it so to query the database with principal we need to install the Prisma client that's going to run prism my generator which is going to generate the Prisma client that's unique to your project Prisma is really awesome because it gives you insane typescript support because of this we're going to install the Prisma client and then we're going to create the database from the Prisma schema so in your terminal you just clear it you need to say pnpm I Prisma client and then I can say pnpx Prisma DB push and we're using npx or pnpx because we don't want to install the Prisma CLI locally so we can just execute the binary and we can say push and this is going to create a schema now I'm going to open Prisma Studio that's a nice graphical user interface for your database and go to the roles table and we're going to add some records and you can do this from inside your app from some user interface but I just want to give you a brief overview how you can use roles right so we can just say pnpx Prisma Studio but yeah let me open it so I can go localhost 5555 and you can see here are our users so this is our table and here are the roles so we can create the roles in advance so I can say add record and I just need to say admin and I can press enter and I can save one change now we have the admin role I can add another record which we can call user and I can save that so let's keep the Prisma Studio open which is going to be useful later and yeah let's continue I'm also going to create a new terminal here so we can just start pmpm run Dev and for the project itself I don't have anything special I just have a layout file for the Styles and I put all the Styles in a global file so we don't get distracted because it's not important right and here is just the home page right and the last thing we have to do is initialize and Export the Prisma client to use it in our project so inside our project I'm going to go to Source lip I'm going to create database TS and then I'm going to import Prisma from Prisma client then I'm going to export const DB new Prisma Prisma client and that's it now you can use it inside our project let's do the user registration to register the user I'm going to use cell kit form actions that's an easy way to write an action you want your form to take once you submit it and return form validation errors cell kit makes this really easy so let's see how if we go to Source in routes I'm going to create our register folder and I'm going to create the page as well and this is going to create the folder and inside is the file so let me just close this and I can close the sidebar and then let's just type it out together so you can say script language typescript and we can say import type action data from types and this is going to complain because it's not generated yet we can just say export let form and we can say action data which is a type so you can get form validations here and other things I'm just going to say register now let's create the form so I can say form and for the action if you want you don't have to specify an action if it's the default one but I'm going to name it just so I can show you the difference so I can say action and then we're going to have an action register and this is really great because when you see something like this you know where the file is located which you're going to create in page server TS in a moment and we're going to give it a method of post and let me just skip this we can rename it to register and let's just add the fields so we can say div for styling let's give it the label for username we can say username and then let's create an input so we can say input type text sure and we can say it's required so we already have some validation from the browser but obviously we need to do check server side so you can say ID username name is going to be username and let's create the same thing so I'm going to copy this lower make space so instead of username we're going to have a password and let's also change these occurrences we can say password and there's also the special type password and this is also going to be required and for the form validation whatever we get from form from our server we can just say if you're going to have if we send user true there we know we have an error which you're going to see in a second so now we can use a paragraph tag we can give it a class error which I have globally and we can say username is taken and now we're going to create the endpoint but before I do that we're going to need b-crip for caching the password so let's open your terminal again let me stop the development server I'm going to say pnpm I decrypt and you're going to install the optional types but if you're not using typescript you can ignore this types decrypt let me start the development server again I'm going to close the terminal so now our goal is to validate any errors there might be and then we're going to Hash the password we're going to create the user authentication token and assigning it a role after which I'm going to redirect the user as you can see here so we can go to the sidebar again and let me just go here and now when you refresh let me just go to the register page and if you go here and a pro tip if you have trouble generating the types you can press Ctrl p and then you can either restart the language server or there's an option to restart the typescript server because sometimes this is buggy and yeah once it's going to generate it should work but yeah we need to create the file right so I'm jumping ahead on myself but yeah if we actually say page server TS and then we can just close this and in the post I have it like this so we can import invalid redirect from swellkit and then we can import some type I'm going to need action actions page server load from types and then I'm going to import bcrypt and let's import the database we created so you can use it right so we can say import DB from lib and it's already Alias so we don't have to deal with path names and now we're going to create something that's typescript specific and that's enums because those don't exist in JavaScript but if you're not using typescript here you can just create a plain object and I'm only creating this to prevent typos and this is really in general a good practice so you can say enum rolls and we can create a string enum so we can say admin is going to be admin they're going to have user which is going to be also user and then I'm going to give it a load function which is going to return later so I can say load page server load going to be async and let's just give it a to-do and then we're going to see what we're going to do later so here are the actions and I like to extract the actions outside of this object because it's more readable to me for some reason I have an easy time parsing unreadable Json API responses but reading logic inside objects for whatever reason confuses me by the app you don't really have to do this you can just type this as actions and you can type your function here or whatever you want so you can say export const actions give it a type and you can just do it like this you can say register you can give it a function here you can do this type if you want but yeah I'm just going to extract this so I'm just going to say here register and then I'm going to create the function as I have it here so I can go constant it's really shame I really prefer regular functions usually but because I want to type the entire thing I have to do it in the arrow function way so I have to say action and then async and now we have type so we can say control spacebar and we should get the types back so we can say request let me just see request and now it knows what this is so now let's get the username and password and we get those because it gave them a name here so this is name username name password and this is how we're going to get them on the server right so this is just the web platform right and then we can say const data so first we need to get it from the form we can say request which is just a structured right so you can say form data see we get also motor completion now we can get the username by data get we give it a string username and then let's just get the password don't get password and that's basically it so now if we submit anything we can just log it out we just do username password and this is server size so it should be logged in our terminal and since we're using our DOT server TS file this only runs on the server so this won't show in your browser console and now we can just say test it's going to post to itself right and then you can say username test password test and that's really how simple this is let me just close this and I'm going to go back here so now honestly a lot of this code here is just validation because I really don't want to skip on this but the authentication code itself is like maybe 20 lines of code so yeah this is just validation but yeah let's get to it so we can just say for example to make sure even if we have browser validation so I can say if type of username for whatever reason is not a string or type of password for whatever reason is not a string and you can check hey is there even a username like is someone trying to bamboozle us what is going on and then we can just return invalid which is provided by Circuit so you can return 400 and then we can say invalid is true and then we can show this for as the form error right but we also have another one we're going to return user true so you can use that and basically this is just a safety precaution and now we can query the database for the user does this user already exist right so let me just save this so it formats and let's create database const user so we can say await and remember this is already typed which is amazing so we can say find unique right this is a method from Prisma we just need to tell it hey where username right and this is going to return as the user so if the user already exists let's return the error invalid 400 we can say user true and this is basically going to exit this function but we can continue if there is no user we can say DB user create and we just need to pass it if you press Ctrl spacebar you can see what options you get and this is why typescript is so insane you can just say data and it's even going to tell you hey I want this this and that so we can say username and this is the same username we got from before right from the form and now we can just create the password hash or we can do this by using await we're going to use bcrypt hash we're going to say password and we can give it salt rounds 10 is okay and then let's create the user of token and we're going to use a built-in method that's okay provides crypto so we don't really need to import some uuid library or whatever we can say crypto random uuid which is fine enough and now we just need to connect this role to the one we created so if you remember here let me just go to the database rolls we created it basically here and we just have to say hey when you create any new user just default assign it to user and it's going to be part of this array and we can later query the user so which user have the user role admin and Etc but yeah it's really nothing complicated so we can just say roll again typescript is incredible say connect and we just have the name field right so look how this maps to your thing so this is name and we just say name here and I have it in the post and we're going to use our enum that we created right so we don't make any typos so by default I want to make roles user right we don't want to create admin by default okay so when all of this is done we just have to say to cell kit hey redirect so you can use row redirect we can give it a 303 status and then we can redirect to login which is going to fail right now because we don't have that page about the registration itself should work so basically that's it for registering the user let's try it out so now they have some feedback from the browser itself but you should also rely on this validation here right because the user might turn off this validation or whatever because they just really need to inspect the code and disable the required so yeah you have to think of the responsible scenario but let's just create test and we're going to say test and we see we're going to get the error because login doesn't exist but yeah everything works fine if we go to our database let me just go to the users it is showing zero because we need to refresh it but if we go here we can see here is test the ID that's created the password hash the user of token created updated and it even has roles so if you go to the roles we can see it has the role of users so how awesome is this and it wasn't complicated at all so I also want to show you how the validation works so remember if the user already exists if you go here and type test test we should get an error because we're having form here and then we can say hey form user remember if the user already exists we're going to return user true and now we know we have some errors on the form so let's say this should say username is taken and awesome it works let's work on the user login that's going to be similar to the user registration page I also want to emphasize that if you have sensitive information like usernames and password be vague with the error messages do not help Bad actors who might be trying to abuse it so try to be as helpful as possible but really don't give specific information like hey this username is invalid or this password is invalid because someone might use this to fish for information but yeah let's create the same thing if we go to source routes and then I can say new file and I can create login same thing as before page cell this is going to create a login folder with page as well and now let's create a script tag so we can import type action data from types it like this and we're going to do the same thing action data and now we're going to have login let's create the form so again for the action we're going to create a login one and method is going to be post again so let's rename this to login and everything else should be fine and let's create the label for the username say username and again we have the same code right say input and again it's required I'm going to create the ID and the ID is important for four so it knows to identify it so when you click on a label it's going to click on the input that's how it works and the name is important to get the information on the server say username and let me just copy this over so now we're going to have password and don't mind repetition right so we can just type instead of text it's going to be password and then again validation errors we can say if form this time we're going to say invalid and this is what I'm talking about so be vague with the error messages let me just see do I get huh sometimes I might work sometimes it doesn't username and password is required so you see I really don't want to be specific what exactly is wrong here which is more secure and then we're also going to return if the credentials are wrong so I can say if form credentials and if you never saw this symbol this basically just means hey this value on the right might not exist so instead of throwing an error just be undefined or whatever so basically that's all that is but yeah we can just create another P tag and we can just say class error and we can say you have entered the wrong credentials and let me just fix this to have it same as I have an example and that's basically it so we're going to create the page endpoint so I'm going to check if the user already exists and compare if the passwords match and I want to generate a new authentication token each time in case it gets compromised because in that case let's say your token gets compromised and then what can you do you have to ask the creator of the site hey can you update this in the database from me and you really don't want to do that right and then we want to authenticate and redirect the user and another awesome thing is as well keep provides a nice API for interacting with cookies so you don't have to import the cookie package because swelkid uses it under the hood but let me just go here and we can create inside the login we can say plus page server TS let me close the sidebar so we have more room to work and now we can import the same things from before invalid redirect I'll send JS kit we're going to need Big Crypt again and let's import the types so we need action actions page server load from types and then let's import our database and let's see it's already smart enough see that's really awesome so you can say database but sometimes it does these weird things so it really does have the job and I'm like okay thank you Thai food is like hey I'm trying to help thank you thanks trip export console save page server load async and again I'm going to tease you without to do so basically we're going to do the same thing right so let me just export cons actions we can give it a type actions and this is even optional here because otherwise you would Define the type actions here so you can have the types inside but really extracting the function so maybe this type here is redundant but up to you so let's create the login and say the login which is going to be the action again async and we're going to give it a body and now we have awesome Auto completion so if I press Ctrl spacebar you can see we get cookies we get the request itself and now we can just do the same thing data await request form data and then you're going to get the username and just digital this and we're going to get the password data get and then again let's do the validation so you can say if type of username not a string or type of password and if someone is trying to bamboozle us that's right and then we can return invalid 400 ml is going to be true and really don't display this on the client but you can if you want I just have it here for posterity but yeah let me just save everything so it forms nicely and remember let's go to the next line so now we can get the user cons user await DB user find unique and now we can say where that username so this is short for username username but you already have the username from the form right so you don't really need it and we can say hey if this user doesn't exist return invalid they're going to give it 400 and remember wake so we're going to say credential credentials true so the type of error is credentials and now we're going to get the user password so cons user password we're going to say our weight bcrypt and bcrypt has a compare function so we can say the password that was provided to us let's compare it to the one from the database user password hash and then we can check if the user password doesn't exist we can return invalid again 400 credentials true and now we're going to generate a new off token just in case it gets compromised and this really isn't anything hard so you can say const authenticated user we can say await DB user and how we update our record in Prisma simple to just say update we have to specify where username so we get this from the user username and then we can give it the data we want to change so we want to change user of token and then you can use the built-in crypto from cell kit we can say random unique identifier and that's basically it so now once we've done this we can create the cookie so we can do that by saying cookies which we get from here remember as well kit which is awesome we can say set we're going to give it a name session but you can give this a name banana whatever you want and we can say one two three four right for the value but I'm going to use the authentication token so authenticated user which we updated the token right now so you can say user of token because that's what it's returned from Prisma and now we can provide some options so we can say path which is going to be for every page and I commented all these options here so you understand what they do and this just sends a cookie for every page and then we're going to enable HTTP only true and this enables HTTP only cookies so you can't get the Cookie by doing something sneaky like document cookie so it's more secure and then we're going to restrict the request to be from the same size so for example the downside of this is that you can be linked from on another page and send the cookies so this is something that you need then then don't use this option but basically this is more secure in general so you can say same site strict we also want to send the cookies only over https but in development we might not have https right so we can check if we're in development we can say process environment so we can compare if the node environment right now is production is going to return a Boolean right true or false and then you need to set the cookie expiration which is going to be a month and remember when you have that option remember me you can even change this programmatically so maybe you have this for a week and if someone checks remember me then you just increase the max age here and that's basically how you do that you can say max age 60 60 I just don't want to give an entire number because this makes more sense it's easier to read right so you can save this and now when we created the cookie we want to redirect the user so we can say throw redirect let's give it a 302 and then we're going to redirect to the home page where you can redirect to admin or whatever protected page you have that's up to you and basically that's it for the login so this should work remember we already created the user and let's go to login so let me just try something that shouldn't work so I can say one two three four and it should give me an error here you have entered the wrong credentials and we're being vague on purpose right this is really awesome and let's try to enter something that exists and let me just open the developer tools I'm going to zoom in hope you can see this let me just go to application let me just move this cookies so nothing should be here so we can say test that's what we had before and you can see the session has be created the value is the token that we have in the database so if I go here to user we can see the password hash the ID and the role that was created right this is really awesome and again I want to stress the reason we recreate the user authentication token each time the user logs in because if someone just copies over the cookies you have it's game over right because they're basically you at that point and if that gets compromised you need to change it on the database level so if the user gets compromised we can just change it for them and that's everything and at first this code might look daunting but if you ignore the user validation basically this is only 20 lines of code to get the user login and registration working so let's see how we can implement the user log out and this is going to be really straightforward to make the user logo at work you only need to eat the cookie and redirect the user so I'm going to just create a page endpoint without the page itself in logout page server TS and you can even use server TSN create your own endpoint identified but I want to be able to use Progressive enhancement later and that would require JavaScript so this is what I decided so if I go here to Source routes I can create a logout folder and I'm just going to create page server TS I don't need anything else so we can close the sidebar and now I can import redirect from cell.js kit and let's just get the types actions page server load and let's create the load function so remember there's no reason to visit this page so we only can redirect so you can just say throw redirect so you don't get not found or whatever and that's basically it and now we can use a default action to not be fancy and we can use this anywhere in our app right so you can say export cons actions give it an action type we're going to use default and let's get the cookies and we just need to eat the cookies so we do that by setting a cookie to expire right now so we can set it to hey remove session we're going to give it blank the value and for the option we have to specify path I'm going to say everything and now expires we're going to say hey this should have been gone yesterday so we can do it by a new date providing zero and that's basically it so we can redirect so remember we ate the cookie here you can say fro redirect 302 and we can just redirect to login and that's going to be it but right now we don't really have a phone where we can use this but we're going to use this in a bit when we create the layout file let's talk about something that might be hard to wrap your head around it first but I'm going to do my best to explain how it works so we have to pass the user data to Pages somehow right because remember those load functions where you had the to-do left we somehow need to get the data if the user is authenticated or not and as you might know each load function has the event right so if we log out the event we are going to get all these options like client address cookies locals platform and request but the one that's most interesting to us is events local because we can store some shared data among the load functions on the pages and make it available wherever you use the load functions and that's really great in our endpoint but we also need to make it available on the client somehow and thankfully in the same way to get access to that information on the client we can use the page store and access it via page data and that only stores the combined data of all the load functions and this may not make any sense yet but our goal is basically to populate locale's user or whatever you want to call it right and pass a user prop to the page store and first you're going to achieve this using the hooks file at the root of the project and let me just explain this to you how this works so basically this is your swellkit app and you have your pages here login register right and this is my mental model of this so this is your page in this box page yourself whatever and around this is this box your endpoint page server TS and it has the load function and this feeds data to your page right so you can fetch something from the database whatever and this accepts an event right and we've seen all those options and basically what Hooks are and a lot of people are confused by this terminology because hooks mean a thousand different things but basically what Hooks in swelter are basically like a man in the middle that intercepts any request you make from the page and you can change that request to whatever you want so for example I have an example in this post let me go here so in circuit a hook is just a file that runs every time the cellkit sir receives a request and lets you modify incoming requests and change your response so for example this is the default Behavior we have the Scandal function and accepts an event resolve and then it just returns resolve event if you wanted to you could turn every page into a banana for example so you can check if event URL path name is the route then you can just return a banana instead of the HTML or whatever and this is how we're going to populate the locale's user so we can make it available in all the load functions and pass it to the page store whenever we create the cookie right the hook is going to trigger is going to check hey if the cookie exists it's going to get it from the database the information we need and then we're going to populate the event locals and that's how this is going to work so I hope this makes a lot of sense because again let me repeat the hooks gives you access to the event so we're going to create the cookie and then it's going to say hey does this cookie exist right okay oh you must be the user that's authenticated let me just make sure and then it's going to populate the locals user and that's how we're going to get it in the load function and in the page store I can talk about this all day but it's only going to make sense once we do it so if I go here to the post the first thing we're going to do is at the root of your projects or source we have to create a hooks.servert yes because this only runs on your server and let me collapse so we can just import type handle from let me just see cell.js kit and then let's import our database because we need it from lib database then we're going to create the handle function export const handle and then we can get the event resolve and let's just create the body so now we get the cookies from the browser cons session we're going to get it from event cookies get sessions if it exists you're going to be like okay so let me just show you this session I didn't save it yet so if I go here let me just open the terminal because remember this is server size so if I refresh this the hook is always going to run right let me see how it complains because let me just see we need to return the default Behavior right all right turn weight resolve event the more you play around to try it out is going to make sense so return bananas or whatever fruit you want and that's the best way to learn but yeah let me go here and I'm going to save it so remember every time this is going to intercept our request so if you refresh this ah we're going to see this is the cookie right this is the exact value we have here and this is how we're going to use this so let's check if the session exists or doesn't exist session doesn't exist we can do the defaults let me just copy this over you're going to need it later anyhow so we're just going to do nothing like as usual and if it does exist we're going to find the user based on the session so we can say await DB user we're going to let me just oh I did stay here DB user find unique and we're going to say where so we can see user of token session remember this is the session that we just returned and we're going to look that up in the database that's it and now to not return any passwords or mistake and remember I said at the starter you can create a separate password table if you wanted to avoid making a silly mistake like this but don't worry we're also going to control what we return in the events Locale so you really have to goof things up to return the password in the client so you're going to say hey select username true and I just want to roll right I don't want anything else so now if the user exists and everything is okay we can say if user so now we're going to populate that event locals and remember what I told you we get the event here and we're going to populate that so we can say event our cars and as I told you this can be banana this can be whatever and you can think up so you can say user and then we're just going to create name user username and we're going to create a role user role name that's the values from the database right nothing special and I already returned here the normal one so yeah we can just save this you can notice there's an error here because we need to create a type and I show you also that in the post let me just go here where was this yeah so let's just quickly do that that's in source so this is if you're using typescript if you're not then you can just ignore this interface locals or locals whatever you want to prefer it user name string roll string we just really need to tell it what it is because it can't know right so that's it let me just close the terminal I'm going to close this yeah so now we don't have any complaints we're going to get type safety and where we left off after the user is authenticated and the cookie is created we can populate event locale's user with the username and role it has told you the event local usernaming is arbitrary you can name it event local banana and pass event local banana equals banana if you want it so since the locals user is now populated so it's available in the load functions we can pass it to our application and to the page store right and we're going to do this by creating the layout server TS file so we're going to create an endpoint for this and this is already done for the hooks file we can close this any routes we can just create a new file and we can say layout server TS let me just close the sidebar and I can say import type layout server load from types so we can now get the locals from the load function and we're going to pass it to the page store by returning it from the load function and that's because remember I told you that the page store keeps all the combined data from the load functions and say export cons load layout server load which is going to be async and then we can get our locals right and let me just do this and let's just log it out so you can see what's going on so we can go here and this should display in the now it's going to display on the server right and so you know here and you can see here we get it back username test role user and now we just need to pass it here like I show you let me just close this so you can just return it we can say return user calls user and that's basically it we can now authenticate the user but we don't have any protected route so let's see how that works so here I have a layout file let me just open layout.12 and I only have styles here the title for the page so let me just import the page store remember this is why we needed it so we can use it on the client so you can say page from app stores and now we get access to this so inside we can create a nav here for example and we can say if there is no page data user then we can say just see attack that we can have this link so we can say login you can see your register and if the user is logged in then we can show The Links admin and we can show the log out and we're going to use a form here as you see to log out the user which is going to eat the cookie and redirect the user yeah so let's do that you can also use a nails but I'm really not a fan of that I just prefer to make another if blocking that's a lot more readable to me but you do of course page data user so if the user exists right we can just create a link I've been really going to create that in a moment and then let's create a form it could be simple the action is going to be log out which is going to be posted we can use this anywhere on our page right now so we already have a submit Villages give it a name log out and I also think I have a class local just it doesn't clash with the other styles so I'm going to include that and let me just go here and let me save so you can see we're logged in so we only see admin log out and let us see if our logout works right we made it before so this is going to disappear here and it should redirect us how awesome is this so now when we go let's say to home we just see login and register right and then we can log in we can say test this is going to create the cookie home and we haven't created the administ so you're going to get an error but the logout works we can also update the other load functions so remember let me just open the register and we can open the page server Ts for register and remember how I have uh to do here so now that we have access to the locals now we can use it here so we can redirect the user if they're not logged in say locales user throw redirect we can say 302 and then you can redirect to the home page and we're also going to do the same for login so you can go page server for the login and we can say if not local storage locals user now because we need to import it right see writer is trying to be helpful and you mess it up right throw redirect 302 yeah and that's basically it so now we can try it out so remember here for the let me see this was the register page right so we can go to register and if you're logged in there's really no reason to show register right so if I go it's not going to show but even if you go here it wouldn't make sense to show the register page right so that works and for the login if the user exists again there's no reason to go to the login because it doesn't make sense but yeah that's basically it so again let me log out see if this works and beautiful so let's create the protected route admin so I'm going to do that let me just close all these files because we don't need it any Star routes are going to create a new file I'm going to create the admin folder and I'm just going to say page swelt let's create a script tag so we can again import the page store from app stores let's give it a title admin and I'm going to show you how you can use the user roles if you want and you can do whatever you want so you can do if page data user then we can log a message we can say welcome page data user name right and here's how you can use your roles so now we have roles so you can say if page data user role is equal to admin then we can again do the logout and then let's give it a post you can say log out and before we do that I also want to make sure that to redirect the user if they're not logged in so for the admin page which is right here I can create an endpoint page server TS just close it then I'm going to import redirect search let me see so jskate right I need to import the type page server load and let's say export columns load page server load which is going to be async and get the locals here so there's no locals user we can throw redirect so this is how you can protect your out but another thing is that you can also do it inside hooks as I showed you in the banana examples where we checked if the page is the home page you can do the same thing you can say hey if the user is not authenticated and this is the protected route then you should redirect but I'm going to show you why I'm doing this that way in a second so for example if I go to the page right now we're not logged in right so if I go to admin it will just redirect us nice and if we log in test we can go to admin and we can see we greeted welcome test and let me just make it more exciting because it should be right so let's do another thing where I go to the user and let's just change the role of the user right so you can see roles you will do this programmatically in your app of course but I just want to show you the simplest form of it so you understand what's going on so let's just change it to admin we can just do this then we can say one change and this shouldn't update now because oh it's going to update that's nice so now the user is admin and let's just do it again just so we can see it so we can test and this is the admin now so we can go to admin and now we have admin only features so we can log out from here and how awesome is this I also wanted to mention that in the final example I used a cell kit group to group The off related routes inside on off group and the protector routes inside a protected group so if we go here let me just collapse everything so it's easier to read so inside routes you can create what's known in socades groups and groups are folders but they don't create new routes so you can create a folder you just see I named it off so you can put your off inside here we had login logout register so you can place it inside off and then we can create a new folder protect it and just so you know to differentiate them so basically that's it and there really isn't any change to functionality these are new routes and everything should work the same so you can log in edit test and go to admin log out but yeah basically groups are a nice way to organize your routes let's talk about Progressive enhancement have you noticed how so far we didn't use any JavaScript and that's really true I can for example press Ctrl P I can type JavaScript I can disable JavaScript and let's go to the register and we can create another user so we can say whatever and it works as before so you can log in as that user and we don't have admin privileges right but we can see the admin section and we're doing this all without using JavaScript and a point isn't to not use JavaScript but use Progressive enhancement so your apps are more resilient so your JavaScript fails for whatever reason your app is going to work the same but if JavaScript is available we can progressively enhance and improve the user experience so let me just enable JavaScript back on and you're going to be surprised how simple this is in circuit even though it might sound complicated the only thing you have to do is import the enhanced action from circuit and is going to progressively enhance the form and use JavaScript when it can so let's go to the register page so we can type register and then we can see page as well for register and we just really need to import enhance so you can say import enhance from air forms and the only thing you have to do is use the action and that's it so now when JavaScript is available on the page it's going to do all of those shenanigans that you would otherwise do in JavaScript Frameworks like event prevent default and it uses client-side rendering instead of refreshing the page so it's a smoother user experience but we need to do something different for the register page because for example right now let me just log out so if I go to register here and you're going to see how the transition is smooth so for example I can just create another one and we shouldn't get a refresh yeah it's going to go to login so now let's also do it for the login page if we go here we can just import enhance from what was it again it was that forms see yeah it forms and then we can just use it here hence and I can save this but I'm going to show you a problem so we can register the user right and then we go to login for example you can do test and remember now we're using JavaScript and this is going to work of course when you press login but not updating the UI it updated the other values in the background like locals so for example this is happening because if we go to for example login and we go to the load function here basically to solve this problem we need a way to rerun the load function for the pages somehow right so it's going to rerun this it's basically going to do the equivalent of me refreshing this because now it updates C and we can do this using invalidate all and then we're going to supply a custom return function that's going to give us the result and basically this overrides the default behavior of the enhanced action so you can say invalidate all which is going to rerun the load function for the page and then since we customize the default Behavior we don't want to re-implement everything using hence does so we can use apply result and pass the result back in so let me just go here I'm going to close this page and this really sounds intimidating but it's really nothing special so let me just say equals brackets and then we can just pass this function and this returns an async function which is going to give us the result and you can also get access to other things inside here let me just see you get action cancel data form so you can do some loading States or whatever you want and it's really useful for this but I would advise you to read the documentation to learn more but yeah so we can do invalidate I already imported let's validate all yeah nothing valid you know anything so you can say invalidate all I really can't use it outside here because we need to get to the result after everything is done right so you can say invalidate all and then we want the default Behavior again so you can say apply action result and we can save this and now we also need to do this for the logout and if we go to layout where our log out this we don't need to do the same thing here so I'm just going to import those things import apply action oh awesome enhance our forms and then we're going to say import invalidate all from app navigation and that's basically it so we're going to do the same thing here where we have our form we need to use enhance especially the function we're going to return result give it to body then you can say invalidate all I'll wait apply action I'm going to do it for the result and also let's fix the mistake here so yeah I hope this makes sense and now everything should work properly when JavaScript is disabled and when it's not so let me just close all of these things because I think we're done here let me open the console back again let's first try it with JavaScript disable so we can see just log out of here you can see register you can see we can do it here so for example for some reason JavaScript is not available you can see everything still works when you go log out and now let's bring JavaScript back in and I'm just going to refresh it for good measure the radius are going to work and again if we have some errors username is taken which is really great if you register the user and now if I type some wrong credentials we can give vague but helpful information let's close this and now we can log in here this is going to redirect us and now we can go to the admin and we'll also admin and the log out should also work so regardless which one we press it should log us out and update the user interface so you can say log out and everything works hey that's everything to authenticating users with cookies in circuit I hope at least you found the video educational and learned more about circuit because it's mostly about just using the web platform if you have a serious project I will look into using an authentication library because security is hard that you don't want to run into edge cases and maintain one yourself so you can look into swellkit off and Lucia which are great libraries for authentication in toolkit thank you for watching and catch you in the next one
Info
Channel: Joy of Code
Views: 21,123
Rating: undefined out of 5
Keywords: sveltekit, authentication, cookies, tutorial
Id: E3VG-dLCRUk
Channel Id: undefined
Length: 54min 10sec (3250 seconds)
Published: Fri Sep 30 2022
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.