SvelteKit Authentication with PocketBase

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
what's going on everyone my name is Hunter and welcome to a brand new spell kit video in today's video we're going to learn how to set up authentication using pocket base and spell kit now if enough people are interested I will start a mini series on pocket Basin spell kit where we'll continue to build off of the work we do today and we'll try to cover as much as possible while building a small application so if that's something you would be interested in please leave a comment down below letting me know and without further Ado let's go ahead and get started now for those of you who are unfamiliar pocketbase is an open source backend and one file and if we look at their documentation here we can see that it contains an embedded database using sqlite with real-time subscriptions built-in users management a convenient dashboard UI and simple rest ish API and also says that the easiest way to get started is to download the pre-built minimal pocket base app which we're going to download the Linux version because I'm running on WSL and before we do that though we actually want to read down here and we can see that pocket base will automatically create a new directory alongside the executable to store your application data in settings so with that in mind we're going to want to create a new directory before we actually go and download and extract this executable so that the data is kept with the project that it belongs to so we'll right click this Linux link here and copy it and then I'm going to open up my terminal I'm going to make a new directory called spell kit pocketbase off and then I'm going to navigate to that directory and then I'm simply going to type curl Dash L Dash o and then I'm going to name this file PB for pocketbase and then I'm just going to extract or download that zip file here and now since this is a ZIP file we actually need to extract it so I'm just going to say unzip PB and then you're going to see if we run an LS here we can see that we just have the zip file still we have a license for pocket base then we have the pocket base executable so what we want to do first is I'm just going to remove that zip file because we don't need it anymore whoops and now we have pocket base and license inside of our directory here so what we can do is we can now just run that dot backslash pocketbase serve and you can see that we now have a server started at 127001 80 90 which is localhost 8090 and we also have the rest API running as well as the admin UI so we can click on the admin UI here and actually navigate to the admin UI and check it out for a second so it's going to first prompt you to create your first admin user in order to continue so I'm just going to do that now once you do that and create your account you're gonna be brought to the collections page which is currently empty and collections are essentially tables in our database so we don't need to create any collections at the moment so let's move on to the users page and this is where our users collection lives so as you can see at the top we have different fields that come by default which include ID email profile.name profile.avatar created and updated so if you notice these two Fields here profile.name and profile.avatar have profile in front of them when the others do not and if we look at the pocket-based documentation and we click on manage users we can see that by default all user models have the following properties which is kind of what we just went over here except we didn't see the verified and last reset all the verification Fields but it says that in addition to above properties pocketbase allows you to add as many custom Fields as you want using the system profiles collection the user Fields will be appended to each user model under a new profile property and then it says that the only difference between the profiles collection and a regular one is that it cannot be deleted or renamed so if we look here in the in our admin dashboard and we click on this Cog wheel we can see that we have name and Avatar here and you can see that the collection name is profiles right so this is a system collection now I do want to make a note here that if you're watching this video potentially weeks or months from the time it was released I would definitely check out this issue here that was open it's a discussion about merging users and profiles that the maintainer has opened up for feedback there's been some back and forth going on but they haven't actually came to a resolution as to whether they're actually going to do it or not and you'll see why maybe they should do it here in a minute when we actually set up our accounts because there is an extra step that is required whenever you go to create a user but definitely go and check out this I'll have this Linked In the description below to make sure that nothing changed if so I'm sure they're going to have a migration guide that should make it easy to kind of still follow along with the rest of the video so now that we have our pocket based server running let's go ahead and get started with the spell kit integration and I've went ahead and prepared a starting point for us which I've styled using Daisy UI and Tailwind CSS s it just includes a simple home page a login page and a register page and to get to this point all you really need to do is to clone the repository that I have Linked In the video description so what I'm going to do is I'm going to open up a new terminal window and I'll show you how to do this and we're going to repos I think it's spell kit pocket base off and then inside of this directory we're actually going to run git clone I'm going to do a single branch and then the branch is going to be starter and then it's going to be get at github.com Hunter byte slash svelt kit pocket base off dot get all right so now when we look we have this directory here again it's just the starter branch of the final code repository so if you want to start where I'm at right now feel free to do so and follow along so we're going to navigate into that directory now and we need to install all the packages again really the only packages that I've already installed is Tailwind CSS and DayZ UI so everything else is pretty standard skeleton spell kit project right so now that's all installed we're going to open it up in our favorite editor which is es code and as you can see we just have a few routes here we have a couple page.svelts we have a login page.server which is empty and then a layout which just includes the one of the days UI nav bars and a home page and then for the login page again I'm just using days UI components there's a couple inputs for the login which is email and register or email and password and then for register we're taking in a name email password and confirm password so let's go ahead and run this and just see what it looks like so if we navigate to localhost 5173 you'll see that we just have a very standard simple home page here we also have a login page and a register page now none of the backend functionality has been implemented yet I just wanted to go ahead and get some of the initial styling done and structure done because that's not really the focus of the video which is authenticating with pocket base so we're still going to implement all the backend code together I just wanted to get this set up in advance so now if we go back to the pocket based documentation we're going to look for their JavaScript SDK and if we look here on the sidebar it's going to say client-side integration we have some sdks and it says that the easiest way to integrate is use one of the official SDK clients our JavaScript SDK supports browser and node which is what we're going to be using so let's go ahead and click on that and it's going to take us to the repository and I think I can zoom in further here and get the full readme so we can see that we install it via npm using npm install pocketbage.save so let's go ahead and do that now so let me open up a new terminal here and install pocket base okay so now that we have pocket base installed let's look a bit further into this documentation and kind of see exactly what we're working with so if we scroll down a bit we're going to see a usage example here where they show us creating a new client which instantiates a new pocket-based instance but that's not how we're going to do it because we're using server side rendering right so we'll get to that here in a second but if we keep scrolling down we can learn a little bit more about authentication with pocketbase so we can see here that the SDK similar to you know super bass or Firebase it keeps track of the authenticated token and auth model for you via the client.au store instance and then it shows an example of this base all store which client.au store extends right so you can see here that we have token which is the authenticated token we have model which is the actual user or admin whoever's logged in with that off store and then we have is valid which essentially will return true or false whether the person is actually using a real and non-expired token then we have a few different methods here one of which is clear that we're gonna be using to log out the user or admin we're going to have save here which we're not actually going to use because of the fact that we're going to implement it a different way we also have on change which allows us to register a callback that is fired on the store change we also have two methods here that we're definitely going to take advantage of and I believe when I was reading through all the issues and discussions these were built specifically to help with server-side rendering to kind of make the process a bit easier so the load from cookie method takes in a cookie header and then it looks for it takes in a key which defaults to PB off which is the default key that that cookie is is passed to the client with and then we have an export to cookie which we can create a cookie from that I'll store data so we're going to talk a little bit more about this here in just a second when we get down to the implementation so let's scroll down a bit further foreign talks about the SSR integration so of course there's no one size fits all because every framework handles it differently but in general the idea is use a cookie based flow so we create a new pocket based instance for each server-side request so if we look up here at the uses example they create a single client and they kind of used it throughout the application right but for us we're going to be creating a new one on every single request and we're going to implement that using Hooks and if we scroll down a bit further you can see that the they have actually have a Spoke kit example where we actually implement it inside of the hook handle function the handle function for those of you who don't understand what the handle function is I know I haven't made a video on that yet but essentially it runs on every single request to the spell kit server so even on server side requests so what happens is it essentially intercepts that request so it's like you're able to add essentially middleware to your spoken application that's essentially what this is so it takes in an event which is the request event and then it also takes in a function called resolve which will render the route and generate a response so the first thing we're doing is we're accessing the locals of that request right and we're setting event.locals.pocketbase to a new pocket based instance which will then have access to inside of our load functions inside the rest of our server side application right and then we're going to load the store data from the request cookie string so basically if there is a cookie we're going to grab it and we're going to pass it into this load from cookie function which if you recall up here this updates the store with the parse data from the cookie string so essentially it's going to rip the cookie out of there it's going to check for this PB underscore auth equals key and then if it exists it's going to then update the off store with the data from that cookie so if I'm logged in that also is not going to have myself as the model if someone else is logged in it's not going to have them as the model and then if there's nothing here obviously it's not going to have the is valid is going to be false there's not gonna be anything in the OS store it's going to essentially be a bunch of empty strings right so then we're going to generate a response which then all the server-side actions that we have set up are going to happen right as it resolves this event and then before we return that response back to the client we're actually going to update the header so we're going to set some headers we're going to add the set cookie header and we're going to run this export to cookie method which if we see here exports the store data as a cookie with the option to extend the default cookie options essentially right so anything that happens behind the scenes so if we add something we edit a user's profile while the server side actions are happening we're going to have that latest data now back in our cookie so that the next request has that latest data right and then we'll return that response back to the client so let's go ahead and get you implementing this I think it's me best if we start off by implementing the handle function instead of our hook as in order for us to even access that pocket base instance we need to have that set up so let's go ahead and inside of our source folder not the routes folder we're going to create a hooks.server.js and then since we have pocket base installed we're going to import pocketbase with a capital B from pocketbase and then we're going to export the handle function this will be asynchronous and it's going to take an event and resolve just as we previously discussed and what we're going to do here is we're actually going to set event.locals.pb equals new pocket base and we'll say localhost 8090 as that's where our pocket based instance is running right now right and we'll say event.locals.pb.offstore dot load from cookie so we're taking in a cookie from the request headers like we just talked about or nothing and then what I like to do here is this is a personal preference of course but I don't like typing out event.locals.pb.usstore.model just access the currently logged in users information so what I'm going to do is I'm going to set up an if statement here so if event.locals.pb.austor.isvalid I also shorted shortcuted pocket base as well you can see that I just used PB here instead of the full pocket base word you could also use client it doesn't really matter we're going to set the event.locals.user equal to event.locals.pb.offstore dot model now man that's a mouthful all right so now we're going to generate the response and then we're going to set those headers and I'm actually going to add it to do here to remind myself to secure this cookie before deploying um because we're going to set it on secure cookie because our server is not running on https so let's just say response dot headers dot sets and we'll say set cookie to event locals PB off store export to cookie remember that method we talked about and then I'm just going to set some cookie options here we can see here that these are the options we have available to us I'm just going to say secure is false for now and then I'm going to return that response all right so now that our Hook is in place we actually need to learn how to create a user right because we have a register form here we don't have any actions set up for it yet or anything like that so let's go into our documentation here and let's look for the web API users and if we scroll down here a bit we'll see they have a create user option here and they show an example using the SDK so we can just await client.users.create and then we can update the profile which we're going to do it a little bit differently than this and then we're going to send the verification email which we're not going to do in this video either but we may do so at a later time if that's something you guys would like to see so that being said let's go ahead and look at our register form page that's about here you can see that I already have I believe an action set up for register right so we know that we need to hit the register action in our page.server.js under the actions so if you're not familiar with how form actions work in spell kit I have a video related to that please go check it out it'll definitely bring you up to speed on how this works but we're going to export const actions and it's an object and we're going to set register excuse me asynchronous and it's actually going to take in locals right as well as requests now if you recall we have the PB instance stored in our locals so that's how we're actually going to call these client um dot users.creator in our case it's gonna be pb.users.create inside of this action because we're receiving it from the request through the locals right so now what we can do is we can actually access the form data so we'll say cons form data equals await request dot form data and then we'll say const data equals object Dot from entries and then we'll just pass in form data like this which will give us an object of the form data and let's just test this out real quick to see what we're getting back go to our register form here and we'll go back to our console that's running the application and you can see here this is what we get back inside of that a nice structured object right so now we actually need to run this awaitclient.users.create right so we're going to use some try catch blocks because all of these pocket-based services use standard promise based responses so we have to catch the errors like that and then log them otherwise our application will break if it experiences an error so what we're going to do is we're going to open up a try block here and we're going to say cons new user equals await locals.pb.users.creates and then we're going to pass data into it right now it doesn't matter since if you if you check here on the right you can see that we're showing me passing in the email password and password confirm but if you look at our name here is is listed as an object property right we can just pass that over there and they will strip it out without us having to do anything right but it will not update the name for that user just yet all right so then we're going to do is we're going to take out token and user from that created user so we'll say await locals.pb.users.off via email and what we're doing right now is we're essentially signing in as that user that just registered right and we have to do this in order to update the profile name and that's one of the reasons that the maintainers are discussing potentially merging these two together so you don't have to do this process but that's what we're doing so we're going to say data.email which is the email and then we're going to say data.password which is the password right and then now we have that user what we can do is we can say cons updated profile equals await locals.pb.records.update and we want to update the profiles collection right so this is the standard way to update collections or to create or update or read collections in Pocket base is we do pb.records.create update list so we're going to say update and this is the collection we want to update we don't take the profiles and then we want to update it where the user.profile.id which is this user here their profile ID and then we're going to pass in the object so it's going to be name is going to be data.name and now we're going to sign off the user because we either want them to potentially verify their email before they can sign in or we just want them to resign in to make sure they remember their credentials we can say locals.pv.store.clear and then if we catch an error we're going to console log the error to our console here and we'll return error is true with the message of error and we could use that later with our forms for validation or for displaying an error message or whatever right and then if it's successful so if everything goes well we want to throw a redirect which comes from spell JS kit and we're gonna go to 303 and we're going to slash login so essentially they register for an account now we want to go log in on the login page all right so now let's just see what happened here so let's go ahead and log in and we'll check our pocket base instance as well once we create this account so let's just create an account we'll call this Walt White you guys know like my Breaking Bad references and password password registered okay we got redirected that means we did not have any errors during that within that try catch block so let's go into our pocket base admin UI here and let's refresh the users and as you can see we do in fact get this user created so it has an ID and the name was passed as well right which is awesome so now that we have this user what we can do is we can actually go and set up the login route to allow them to log in so let's go into our login page here page.server.js and we'll also export const actions and we'll say login takes in requests and locals and then we're going to do the same thing so we're going to take in the form data request.form data and then data all right now we're going to run a try catch block again and if you noticed we actually already ran the auth via email method here we're gonna run that again over here so we'll extract the token and the users let's just set up a try catch block first the reason I add these is because you get these back when you log in that user so you can pull out the user or the token and do whatever you want with it when they log in I'm not really sure what the use case would be but it's there if you need it and then we'll catch any errors and we'll do the same thing we'll console log the error and then we'll return error is true and email is data.email and again we're passing these values back to the form so that we can access them using that form prop with our form actions so again if you're not familiar with that I have a video related to that please go check it out so you're not confused okay and then if it's successful we want to throw a redirect to the home page right they now have access to the home page and I just got an error here it's because I didn't actually import the right redirect so let's just take that out here and then now we're good to go okay so now let's go ahead and log this user in so let's go over to our sign in page here and we'll use the account that we just created wallet example.com and password and we hit enter and now we are at the home page right but that doesn't really give us too too much information so what we can actually do is access some of that user's data inside of our application somewhere else that we can actually see that we are in fact getting that used information and they are in fact logged in so what we can do here for this example we may change this later but we're going to create a new file in our routes directory and we're going to call it plus layout.server.js and then here we're actually going to export a load function so export cons load it is going to take in locals and if you recall we actually set locals.user to the ostor model so we can check here we can say if locals.user and locals.user.profile so if that user does in fact have a profile we can return some information about that user and let me just demonstrate what would happen if for example I just returned let's just say a prop of user and I returned it as locals.user right I hit save you're going to see that we actually get an error it says cannot stringify arbitrary non-pojos which stands for Plano JavaScript object and a plain old JavaScript object is essentially a just contains data it doesn't actually contain any methods or internal State and if we want to see what this locals.user looks like we can console log that here so it's console log locals.user and I'll omit this return statement here and let's just save the page and if I refresh it and as you can see this is what we get this is not a pojo or a plain old JavaScript object we have some ends here so how do we convert that into a pojo now one of the easiest ways is to just simply say let's just say console.log we can say Json to parse right now we can't parse this right away we actually have to stringify it first and then we're going to parse that stringified non-pojo essentially right so we can say json.stringify and then we can just say locals.user and now let's just see what this looks like so as you can see now this is actually a pojo so we can return this back as the user's profile and now this will work fine if we're not using typescript but if you want to try to preserve those types because everything we get back from our pocket base is going to essentially look like that we're gonna have to kind of parch and then stringify it so what I would recommend doing is to give yourself a little bit more control over the object what kind of response type it returns let's create a new method instead of lib called helpers.js and we'll just export a new function called serialize non-p-o-jos and it's going to take in an object which is going to be that non-poj object and then we'll return json.parse json.stringify the object right and this where you can specify some return types and do a little bit more manipulation with those different objects you expect to be receiving back from pocketbase so now we can go back into our layout.server and we'll use that function we just created instead so I'm going to import serialized non-pojos from lib slash helpers and then instead of running this console log here we're going to replace this with a return statement and we're going to say return profile is going to be serialized non-pojos and we're going to say locals.user.profile and then since we added this to the layout we're going to have access to profile inside of every page in our spell kit application so let's go into for example the home page here let's go here and what we can do is we can actually update this page.s felt route so we can just say accept the dataprop first and then we'll say welcome to the spell kit and pocketbase project we'll put a comma we'll say data.profile.name and then now you can see it says welcome to this folkit and pocket based project Walt white so now that we have access to that we can also adjust our layout here so that it doesn't show login and register when the user is already logged in right we probably want that to say log out or have a profile picture or something of that sort up there so let's just change this to a log out button and that'll be a good time for us to implement our logout functionality right so we can add that to our layout.flow so let's go over there because we now have access to that data prop so we can actually accept data here and then what we're going to do is we're going to set up an if block where if there is a user.profile then we want to show the log out button and if not we want to show the login register now you can see here we have login and register twice one of them is the mobile menu that these ui's nav bar provides us with if we make this smaller we can see that we have login and register here as well so we can update that too but first let's start out with the buttons at the top so let's set up an if block here so we'll say if we'll say data dot profile so if a user does exist is if there is a data.profile we want to show a logout button and then everything else we want to show these two buttons right so then when that if statement and we're going to add a form here right because we're actually posting to our own server so we'll say form and the action is going to be a slash logout the method is going to be post and then we'll add a button inside of this form and we'll add a button BTN Dash primary and we'll say log out so now as soon as we hit save you're going to see that we now have a logout button in the top we no longer have the login and register buttons right so then we can come up here and essentially copy this here and we'll come up to our mobile menu and we will add this if statement and then inside of this we're actually going to wrap this in An Li and we'll bring that down and then we'll end the if statement right beneath the last Li okay and then instead of styling this button like this we'll just remove the class altogether and then we can take a look at what this looks like so if I drag this back all right we can see that a button is still there so now let's go ahead and implement this and we're going to use an endpoint to take care of this for us so we're going to come into our routes and we're going to create a new file we're going to log out and then plus server.js right because if you remember from the documentation in order to actually log a user out if we look here within our off store we have this clear method which logs out the authenticated user or admin so we're just going to make a post request to this endpoint and it doesn't matter who is logged in is just going to clear out the auto store clear out the user that we have currently set in the locals and then redirect them to log back in so let's go ahead and do that now so we'll say export cons post equals we'll say locals and then what we're going to do is say locals.pv.offstore.clear locals.user because we set this ourselves if you recall inside of our hooks we set locals.user we're going to clear that as well we're going to set that to undefined and then we're going to throw a redirect to the login page so now let's go ahead and test this out and see if it works so if we click log out actually before I click that let's just look here at our application within our developer tools and we can see here that we have this PB auth cookie right so I want you to know this is what is being pulled in by our hooks on every single request to see who we are and set the correct off sort data for our subsequent actions right and then we update that after those actions occur we then update that with the latest cookie so in our case in this case it's going to take in Walt's Walt whites cookie and then we're going to log him out which means it's going to return nothing essentially as the cookie for that store so we're not going to have a cookie at all anymore and then the user will have to log back in in order to actually regain that cookie so we can click on log out and you can see that the cookie was cleared right now if we go to the home page um let's refresh the page here you can see that we get an error that's probably because I didn't actually check to see if this exists so we'll say data.provot.name and then we'll say else we'll just put this here so now it's just going to put nothing if if nobody's there so now we have no cookie and the user's not logged in now let's just say that if a logged in user tries to go to login or register so let's go to login let's log back in now I can still access log in just fine even though I'm already a logged in user right so let's talk a little bit about trying to protect some of these routes and this could be implemented on any page or at the layout level however you would like and again if we do decide to move forward with this mini series then I'll add some of that into the application as well but for now let's just protect the sign in and register routes from our authenticated users so inside of our routes the register and login we'll start off with the login we'll come into our page.server.js and we'll export a load function we'll take in locals and essentially what we're going to check is we're going to say if locals.pb.offstore dot is valid right because if you recall that returns a Boolean that's either true or false true if they are authenticated false if they're not authenticated so if it is valid what we want to do is we want to throw a redirect to back to the home page right so now we you can see that we instantly got redirected right because I saved the page but if I try to navigate now to login you'll see that we cannot even get there redirects us now if we can do the same thing here on the register route as well so if we go to register you can see that we are doing the same thing here we cannot access the register page so you can do this again at the layout level or at the page.server.js level depending on how you want to structure your application so I think that's going to conclude the authentication with pocket base and spell kit video we've learned how to not only register users but also how to log them in we've also learned how to update the profile at the same time of registration we've learned how to set up our hooks to actually get that cookie out and return that cookie back to the user after the actions have been taken place and we've also manipulated some of the UI with the conditions of whether the user is logged in or not if you guys would like to see me continue this project and you know add some current operations or whatever you guys like to see please let me know in the comments below and if you have any questions you can also ask them in the comments below or join the Discord server we've been gaining members every single day and people are always willing to lend a hand and help out others so with that being said thank you so much for watching if you got somebody out of this video don't forget to like And subscribe and I will see you in the next video foreign [Music] [Music]
Info
Channel: Huntabyte
Views: 30,960
Rating: undefined out of 5
Keywords: sveltekit, sveltekit tutorial, sveltekit crash course, sveltekit load functions, sveltekit endpoints, sveltekit routing, sveltekit form actions, sveltekit forms, sveltekit actions, form actions sveltekit, +server, api route svelte, sveltekit API routes, svelte routes, layouts, sveltekit layout groups, advanced layout sveltekit, pocketbase sveltekit, sveltekit pocketbase, pocketbase auth, pocketbase users, pocketbase tutorial, pocketbase ssr, pocketbase auth sveltekit
Id: doDKaKDvB30
Channel Id: undefined
Length: 31min 50sec (1910 seconds)
Published: Wed Oct 19 2022
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.