GoLang & SvelteKit Custom Auth, it's Easier than you Think... (FULL EXAMPLE & SOURCE CODE PROVIDED)

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
not too long ago I put out a video where I discussed authentication jwt's how it all works and in that video I came to the conclusion that I would recommend you don't use custom authentication and instead go with some authentication provider like all zero or Clerk or Firebase or whatever you want to use but over time I've kind of soured on that and while I don't think I've fully gone back on it and I think there still is a place to use an authentication provider I've warmed up a lot more to custom authentication so in this video I want to give you an example of implementing a form of custom authentication with a go Lang back end a spell kit front end and just kind of give you my thoughts on it at the end so without further Ado let's get into what we're actually building so before I show you the code I first want to show you a high level overview of what this is what the sort of structure of our app and our server and all this stuff is going to look like well first we need to build out that diagram and there we have it this is the high level overview of the architecture that we're going to be using for this silly little example app now what we're going to be doing here is we're going to be implementing something called session based authentication I'll link a couple articles down below which will give you a good uh give you a deeper understanding of it because this isn't going to be a video going deep into session authentication versus token authentication but the gist of it is when the user logs in they make a request to a server when they hit that server they're going to send back down that server is going to authenticate them and then the server will send out a session ID because what the server has done is it's created a session which is stored in memory or a database or something on the server and then using that session they can hold stuff like the user's information it can store their like name first name last name ID all that stuff it's the kind of thing that would normally be sent down in a JWT but instead of storing it on the client we're just storing it on the server so the only thing that the client gets access to is a session ID this has a variety of benefits it makes it so that you can manage all of your sessions obviously on the server so you want to invalidate a session it's really easy you can just wipe out that session within your database although this does result in some scalability concerns because obviously your authentication and all of your methods rely on some data storage because you have to store that data on the server versus with the JWT you just store that on the client so it's nothing but trade-offs like basically everything so I mainly just wanted to use it because it's a little different and I haven't seen too much on it so we're going to be doing session based authentication and how does that actually work in this application so what you can see right here obviously is we have our svelt kit front end so I separated this out into the front end and the back end now of course spell kit is one framework we can consider this one block within our diagram but I split this up because we got to be we want to be conscious of where different things are going to be be run within our application that's going to be pretty important and this is a concept that I think is super important for everyone to understand with the way the modern web is going even if you have a separate backend like go or a larval back end or whatever you want to do realistically you're going to end up probably using some sort of meta framework for your front end like svelt kit like solid star nexjs next.js Etc and the reason for that is because you want to have these server-side capabilities you want a server that's directly attached to your application which will allow you to do things like server-side rendering it'll allow you to do data fetching on the server and then send that down for SEO optimization and you'll also want to have middlewares on there for authentication checks and stuff like this it makes your application a lot better and it gives you built-in routing and all this stuff so really you're going to have most of these but we got to be conscious of where things run so the front end is what's being run on the end user's device when I go to svelt gocustomoff.fakeapp.whatever I'm going to be loading that client-side code so that is what's right here and then the back end code is what's going to be sitting in Versa or Cloud flare Pages or whatever and those are the JavaScript functions that would be within our spell CAD app those would be the plus page.server.ts files or whatever all of of that is executed on those servers or they're the API endpoints that we can create in our spell app so we want to make sure that those two are separate and we know where those things are headed so let's start with the life cycle of a login request what happens when I log into this app so I'm going to load into my spell kit front end app and I'm going to go to slash login or sign in or whatever I called it and then I'm going to make a request I'm going to fill in my email my password and then I'm going to hit send and that is going to be sent to this felt kit backend so the first thing we do is we send it from here to here so that's getting sent up to the spell kit back end let me switch the color here okay so we send it up to the spell kit backend and that is what's going to actually end up communicating with our go fiber backend and there's a reason for that so once we do that we need to actually send this up to our golang backend to check it so we take that here we send it out to this back end and then this back end is going to validate that I'll show you that code later but within here we're going to validate this code to ensure that you know they are who they say they are their email is correct and their password is correct we're going to be hashing the pass password using the bcrypt library obviously you should never be storing your passwords in plain text within your database so we put that up into our goaling fiber back end then we're going to have to you know do the checks so the checks are going to require us going to our postgres database we have to make a query here where we select all the information for the user we fetch that information and then postgres will send it back to our golang API so then it'll get that it'll check it and assuming if it's right then they can log in and now how do we actually log in remember we're doing session based authentication so that means that we need to create a session for the user and we're going to store those sessions within a redis database so redis is a key value store it's a hyper performant memory database it is stupidly fast way faster than SQL or anything like that but the reason why you wouldn't use that as your main database is because it lacks a lot of the really powerful features that postgres has or MySQL has or whatever is very much typically used for like cues or whatever and it's used to just store key value pairs so right here we have a really clean key value pair of our key is the session ID and our value is the user's information which would be their first name last name ID and email in this example so once I've done that I'm going to send out to my redisdb I'm going to say okay I need to save this I'll be like great you did that and now I have my session ID generated and I can send that back down to my spell Kit app now when I send this down this is when things get tricky is we want to make sure that we're doing this in a secure manner because you have to realize what we just created is effectively a key to our app this session ID can be used to get to anything this is a protected this is really important because if anyone got access to that session ID they could impersonate that user and do anything that the user does it doesn't really matter for our silly little to do app but imagine this is a bank app that's a really big deal if you can get someone's session ID for a bank that's why you get logged out so quickly from Bank apps is they're invalidating yourself sessions to ensure that you can't no one else can get into your account no one can steal it and then use it so what we're going to do there is we're going to send this down actually as a header so this is going to I'll make a note of this here so we send question ID as a header now some of you who are more experienced are likely confused by this because typically speaking the general Dogma with um sessions and stuff is to send them down as cookies and the reason for that is because we can do security on the cookies and that kind of thing you have to remember we are in meta framework Bizarro weird world so we can send this down as a header and then we're going to set the cookie on the spell kit back end so we send down the session ID as an authorization header we pull that out once on the response from the spell kit back end and then we're going to set a cookie but we're going to be very careful with this cookie because cookies can be technically accessed from anywhere there's this thing called cross-site scripting or all these different things I'm not a security expert by any stretch of the imagination go go do detailed rating if you really want to get into it but the gist of it is we want to make sure that our cookie can't be used by some other sites JavaScript or whatever so the way we do that is we set the cookie to be HTTP only and we set it to be secure so that means that it can only act be accessed over https and it can only be accessed over through that site we make sure it's same site do all that stuff so now what we're going to do is we're going to take this session ID we're going to save it to a cookie we're going to write that cookie to our app itself and send that back down to the front end so now we've gone through all this stuff and the cookie is now saved on the front end we're logged in and then now anytime the front end makes a request it can just send that it'll send that cookie up and then that the spell kit back end will pull that cookie out it'll send that as an authorization header to our goaling back end and then we can authenticate it and we can authenticate our requests we can get the profile information it's super clean I know that this is a little complicated and a little weird and obviously if we cut out this little man in the middle it would be quicker but the reason why I do kind of like at least on paper having it work this way with it being a header coming out of here is because this makes it really easy to handle like mobile authentication or something like that because now if I had let's just say we want to throw in oops sorry let's say I want to throw in a react native mobile app over here so we want to throw that in here um app well then it's really easy we can just use the exact same thing because we can do Secure Storage on the native app I need to do more research on this don't take anything I say about mobile authentication anything that is Gospel but generally speaking from my understanding is we can access a secure store on the mobile app and then we can just grab this header grab the session ID and then store that within our native app and then connect everything up accordingly so that's a high level overview of the authentication and let's take a look at the actual code the best place to start I think is going to be on the go fiber server now this is not going to be a full breakdown on the fiber server itself because this is an ongoing series uh make sure you guys are subscribed to see everything that's going to be coming down the line and just for today we're going to be talking about the authentication side of this but pretty soon I'm going to go into detail on the structure of this how I structured this app and how I got everything working super clean and super nice with dependence dependency injection and all that stuff I'm really really a huge fan of the way this is set up but all that aside let's talk about how this actually works so if you remember from the earlier example in the diagram what we have to do here is we need to have different routes to handle different behaviors so let's first take a look at the sign in route so I'm just going to go within private handlers users and then let's go into the sign in user Handler so uh let's sign up um we won't talk too much about yeah okay so signing in the user so what are we doing here we're going to go ahead and as I mentioned earlier we're going to take in the request body which is going to have the email and password do all that stuff we validate it here and then once we've done that we need to grab the session ID from this little session manager I built and I did all this basically custom I built this special little um let me do this vs code doesn't yell at me so I made this special little off package and then in here I created a session manager and the session manager has some really useful methods for managing the sessions within our backend so up here our session manager is going to have access to a redis client and is going to have access to a postgres connection so what we can do in here is we can either generate a session or handle like sign in and stuff like that so for this method we're going to be handling sign in so what I do here is I take in email password and then we're going to go ahead we're going to fetch the user right here this is just using raw SQL and the PGX package this is something that I'm kind of debating and going to go in into more go kind of has a data layer problem where there's no Prisma or go there's no super nice orm for me personally I'm focused on learning SQL because it's I think it's one of my weaknesses as a developer I don't know SQL at a deep level and it takes me too long to Think Through the actual syntax of it even if conceptually I know it very well so with all that said we're gonna get the user out of the database check if it's there if it's not in thrown air and then we're gonna go ahead use bcrypt to compare the password you know nothing too crazy here then finally we set up the session so remember when I said the session is just some information that we're storing within this redis database and it's key value pair the key is the session and then the value is going to be the actual information of that session which is going to contain the ID and the first name the last name in the email so we set all this session data right here we go ahead and we set that into our redis database and we return the session ID that's important because we need to send that session ID down to the user so what I'm going to do is I'm going to send down the session ID to the end user right here so what I do is I set c.response.header.set authorization into the session and the reason why I'm setting it as a header and not just sending it down as the body or whatever is because in web history and stuff like that headers are not stored I believe um I don't know the exact terminology and all this stuff but it's better to send private stuff over headers so I send this down over a header and then now we can consume that on the front end so let's take a look at the front end this is the little spell to do app that we looked at very recently so if I go ahead and hit npm run Dev we'll go ahead and get this popped up hit this open this up and we get our basic to do app example except this time we've got something cool so we go to slash sign in we get a sign in page and the sign in page will actually do something so before we run it let's look at the code so now that we're in the code let's take a look at how this actually works so remember within spell kit we're doing file based routing and this is a whole series built around svelte svelt kit and go and how all these can work together and do all that stuff really testing out this stack so if you guys want to see more of that I have a lot more coming very soon make sure you're subscribed so we'll go into source and then we go into our Roots directory and let's go check check out the sign in so I have my server and my svelt remember that distinction earlier we have the stuff that executes on the client which is going to be our uh which is going to be the stuff within page.spel we have the stuff that executes on the server and that's going to be page.server so within page that's felt I just have this form no JavaScript in here no state in here no use State No Nonsense because felt is beautiful wonderful framework absolutely love working with this and literally all I'm doing is I have this export let form which I'll talk about later but it's basically just the result of sending the data up and then I have this form right here which just uses forms as the creators of HTML intended because it turned out that they basically got this crap right back in the 90s really they got everything right back then it's insane um but that is another tangent for another day but right here we have our form and then it's got a method to post So then whenever we submit this form it's going to make a post request to this route to slash sign in and it's going to pass in the email and the password so we go to our server this is where the magic happens on page does servers felkit provides a couple of different methods that you can provide and specifically load and actions load is what's called on the page load so whenever I go to slash sign in this load function is calling so when I go to slash sign in if I add it in console.no Soul DOT log hello and then we go ahead and do this I can see right here hello because I just went to that root and I made a get request to it so anytime we load a page this load function will call but now once we call this uh the reason why I'm actually putting something in here is I want to redirect them if they're already logged in so what's super nice about this and having this and the reason why I advocate for using a meta framework or something is because we can do server side redirects to ensure that the user never even goes to a page that they shouldn't so since the user is already logged in we can just pull the session ID because remember we have cookies we set it as a cookie so we can just pull out the session ID if it exists then okay they're already logged in then we just redirect them to me this stuff isn't isn't actually that hard and I kind of overestimated it in the past so it's really kind of trivial to work with this on the front end especially when the framework likes felt now the tricky one here is going to be within actions actions are the post requests that are handled on the server remember this is server side not client-side so what we're going to do in here is we're going to get the form data that's passed in so when we submitted that form and passed it an email and a password we pull those out and then we stringify them into Json I feel like there's got to be a more elegant way to do this but I'm stupid and I wrote this at 4am so yeah whatever it works for now if there's a better way let me know in the comments but for now all we're doing is we're wrapping this up in a body and then we're going to pass that request up to our sign and endpoint so this is hard coded eventually this will all be taken to production in the future but until then I'm just going to hard code to localhost because it's easier and I'm making a request to user slash sign in and that's the route that we just took a look at within the go app so now that we've done this we make a request we send up the email and password it's a post request we send up a content type of application Json make sure it parses correctly and then it's going to validate that and remember it'll send back the session ID as a header so if we got a valid response then what we can do is we can get the session ID out of the header so we pull the authorization header out and then we want to split it up because remember it's in this Bearer format that's kind of just the way they do it I don't know why but it is so we pull out the bearer format we grab our session ID out of here and now we set the session the cookie so I'm if you remember earlier I mentioned that we want to make sure that it needs to be secure and it needs to be HTTP only what's nice about this is spell kit is smart it's smarter than me so when you hover over set you can read the docs here it'll say HTTP only insecure options are true by default except on localhost because obviously I don't have https on my local environment it's not worth the hassle of setting up because you can't access it outside of my network so who cares unless my roommates are trying to hack my to-do app so you know who knows it could happen but so you know so we with all that set we just want to make sure that we set the path to slash which just means that this cookie is going to be available anywhere on the site which is super important because want to go to other pages to get this data which we'll go to in a moment so we just set the cooker and the sorry we set the cookie and then we hit throw our redirect to the profile page so I go in here and then let's just put in my Gmail doc um and then I think this was the thing I used perfect so that's it so I just made John Doe I made this user last night so you go in here and we go to this me page and then suddenly I'm getting all this information so you remember from earlier that session we set this is the data from the session because we're fetching that from the me endpoint so what I'm doing is I'm grabbing the ID the first name the last name the email Etc super nice super powerful so how is this actually working we go into the me page we have once again client server you gotta really important thing that I know I'm hammering this a lot but as you get better you need to get a very clear mental distinction of the client and of the server I've tried to make videos about this in the past but they ended up not coming out super well and I think I'm going to need to try and figure out how to distill this information in the future but for now remember page.s felt is all client side and then page.server is server side so again here this is just the um this is the me page this is what's showing up here I'm just checking if the data is actually fetched because it's possible that we can go to this page not have a session and then there'd be nothing to fetch so I'm checking to see if we have the data if I do I print it out then on the server here we just have our load function so what it's doing in here is it's yelling at me because it's just a type error I don't know why event is yelling at me here it actually it does obviously clearly work it's just a type thing I think it's just the salt vs code extension being weird you could import this from the dollar types package or whatever but I'll just leave the red thing there for now it's whatever so this right here is the load function it's going to be basically the server side get request so basically this will all be executed server side so if we go to the me page we don't have a session obviously you get sent to sign in and then if we do have a session we're going to make a request to localhost users me so let's take a look at that user's me root the user's me root is actually really really simple because all we have to do is just pull the session out of the database so what I'm going to do here is I'm going to first get the user information so we just pull the header off of our authorization thing remember we just set that header back in the on the server side of the client and it terms get weird but we get the authorization header we pull all this stuff out and then we grab our session ID so once we grabbed our session ID we're going to go ahead and just run session manager.get session and this get session method is as dumb simple as you think it is it's literally just grab grab the session from our database and then unmarshall the session into the user session object which is really just telling it that it needs to have this format of ID first name last name email then we go ahead back in here and then we just send that down to the end user and then on our client our client over here all it has to do is just take this down as the response body and then just send that down to the end users because this page.server is just a data Fetch and then we just send that down to our client and then we display it out here so that's authentication that's a very brief overview of all of it I Apollo I know it might not that's a very brief overview of sign in and me there are more endpoints I implemented here like the sign out method so if I hit log out that'll redirect me to the logout page which redirects me to the sign in page really all I'm doing here is I'm just doing some fancy tricks with uh sign out so I'm just I have a server route here but I'm being Fancy with this because there's no page thing but the load function calls anytime you go to a root and it's basically just a get request so anytime I go to like slash sign out it'll call this load function so I can just use this load function to send down data and it basically just gives me a server side function I can use for this it's the kind of fancy thing you can do with this these Frameworks once you get a really good mental model and understanding of where things are running how all of it works but there's a lot that goes into that you need to understand HTTP you need to understand get versus post you need to understand the browser headers all this I mean there's a lot of crap that goes into it figuring out how to distill that into clean videos is going to be a huge challenge for you for this summer but I'm going to try and do it um I think svelp is the one that I want to do with this I'm absolutely loving this framework more videos to come on this obviously so with all that out of the way that very long example this ended up being way longer than I kind of wanted it to be but oops um so how do I feel about authentication so custom rolling your own auth is as you saw there it's not nearly as hard as a lot of people think it is but it's also not trivial it doesn't it's kind of weird and there's a lot you have to think about a lot you have to understand and there really is something beautiful and nice about having the clerk package where I just throw it in there and it just works it'll just handle everything I need no real effort on my end but the problem that you have with this is these things get really really expensive really really fast so that's the main reason why I looked into just custom rolling off and stuff like that is I've got a project coming up soon that I'm working on on my own it's my new startup and a bunch of stuff really really excited about it I cannot wait to show you guys all that stuff um hopefully someday we'll have some stuff open sourced about it and a bunch of really cool videos I'm very excited for that but the point is this is an app that's going to have it's going to need and require and have a ton of users and like clerk pricing is two cents per monthly active user and that might not sound like too much but especially in a b2c type application where a lot of your users aren't necessarily going to be paying especially early on that's really really bad if you have 10 000 users you're paying a lot for just your users Bill and then the more you scale the more insane that gets so I was looking at this and I'm like you know I feel like I should just roll it myself and it also allows me to do things like it just kind of gives you more flexibility and that's a constant trade-off that you have and really the theme of everything should just be everything is trade-offs I mean spelled versus next it's trade-offs Go versus larval versus the next back end it's trade-offs but the trade-offs here for the authentication is you get the ease of use you also get some extra features which are admittedly really nice you get built-in user management you get the ability to set user metadata you get really great libraries custom built for all the Frameworks you want well if that framework is react with Frameworks with services like off xero or Clerk or whatever these features are awesome these features are great they will help you a ton they're expensive and they're limiting you do not have full control over your authentication you do not own your users and you are dependent on them if you want to migrate off an auth platform good luck it sucks and you end up having to set up your data model in a way that you have this external dependency and I don't know how I feel about that this is something that I really go back and forth on and I think at the end of the day you really just have to answer the question is it worth the effort to go through and custom roll this is it's cheaper it's um probably more performant All Things Considered because it's just all in one database and it's all in your own custom thing especially if you're using a highly performant framework like go or something like that it's going to be cheaper it's going to be quicker but it's going to be harder so is that trade-off worth it really only you can decide hopefully this little introduction helps you out if you made it through this Behemoth of a video I really appreciate it um I will talk to you guys very soon with the next part of this where we're going to be working on fetching the data up and down for the to-do's and we're going to start looking into hosting regions how all this stuff works hope you guys enjoyed have a great day
Info
Channel: Ben Davis
Views: 17,844
Rating: undefined out of 5
Keywords:
Id: 50BYTzwC14Y
Channel Id: undefined
Length: 26min 3sec (1563 seconds)
Published: Fri May 12 2023
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.