WebSocket Authentication and Authorization

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
what's up covalents friends I've showed you how to create a super solid websocket server I've also showed you how to authorize your apps using both cookies and tokens and today we're going to be authorizing our super solid websocket server using both cookies and tokens let's get right into it all right so we're starting off with our websocket template repo and the link to this repo is actually in the description below but basically it's a repo that's already set up with a websocket server and it actually already has intervals for paying the client and the server for drop connections or closed connections or dead connections whatever you want to call them but essentially what we're going to be doing is we're going to be adding some authentication to this so first things first what we're going to do is we're actually going to go ahead and install a few packages and so we're going to open up our terminal and we're going to npm I and I've already installed all of our node packages so we're just installing new packages at this point so we're going to install a cookie parser and at type slash cookie parser cookie parser there we go and I highly recommend that you watch uh I I included a video to my cookies and tokens authentication video in the description below as well and I highly recommend that you watch that video before actually doing this particular tutorial only because I go a little bit more into why we do certain things with cookies versus tokens and also how we're going to be using this kind of hybrid model where we're going to be checking for both like our authorization in cookies and on tokens right and so if cookies exist we're gonna be looking there if not if it's coming from something like a mobile app then we're going to be checking for an actual authorization token right or authentication token it doesn't really matter but again we are going to be making sure that we handle both cases because I think that authorization through cookies is still a good way to do things right and so now that we have our cookie parser installed what we're going to do is we're going to create a new folder called utils we're just going to kind of create a little utils file right here so index.ts and we we are going to export a cons called cookie secret and this secret could really be whatever you want it to be we're just going to call it secret for now I highly recommend you don't use secret but this is going to be for both encryption and decryption of our cookies and we're going to be doing HTTP only cookies and again I'm not going to go too much into this watch the other video it's a good one and again I highly recommend that you write your server code to handle both and you know it's it's in my mind it's better to actually have cookies on your web apps and then have tokens on your mobile apps right but again we are going to go ahead and just use that cookie secret there and we're going to create a function called valid token that's going to take in a string and this is where you'd actually do your token validation so if you're using something like Json web token you would use the verify function here and you just verify that it's a valid Json web token it's not expired if you're doing something kind of like an oauth you know access tokens refresh tokens kind of thing um then again this would just be your function for verifying that the access token is valid and not expired and all that right and so for our case we're not going to go into you know actually encrypting and decrypting tokens so I'm just going to say you know TK equals equals test and if our token equals test after it's been encrypted slash decrypted if it's a cookie or if it's just you know an authorization token or that we're sending in we're just going to make sure that equals test and if so we're going to say good to go right all right so we have our index.es we have our utils and let's go ahead and we're gonna just by default kind of go over real quick kind of where the cookie parser normally would go right and so typically in our app router here we which is our HTTP server this is our Express app we would be kind of importing cookie parser here and we would then use that somewhere around here we'd just do a DOT use cookie parser and we'd pass in our cookie secret right and then this would actually decrypt the cookies on your request headers and it would put them as an object and anything that was encrypted would be on sign cookies anything that wasn't would just be on just the cookies property right and I go into that a little bit more in that other video so highly recommend again you watch that uh now this router's file is basically done we're not going to be really living too much within the HTTP router or at least our API router we are going to be going into our socket section here right so this is where our actual socket server exists if you haven't watched the video creating the you know websocket template uh that's another good one to watch we go into a little bit more detail into why you know we do certain things in here there's also the one on heartbeats that's good where we actually create this interval but again we're you know this is essentially the creation of this websocket template right let's go ahead and also add our cookie parser in here so we kind of have a little area already for performing off and so that's basically where we're going to be doing this now we actually need to import our cookie parser again here so let's go ahead and import that um that can be at the top here cookie parser and then we're also going to need just to kind of play well with typescript we're going to need to import a few things from Express so let's go ahead and do that as well and what we're going to actually import is request and response and you don't have to do this we could actually create our own interfaces but I'm kind of taking a little bit of a shortcut here uh so don't get too upset about it but um I'll kind of show you exactly why we're going to be doing this in a second right and so basically what we're looking to do is we already have our area here that we want to be performing off and so first things first we're actually going to parse the cookies and we're going to parse it with our cookie secret and this actually returns a function because it is middleware so this is where we actually want to pass in our request resin next but we don't have request to Res right and so basically we're going to be kind of spoofing the response so we're just going to pass in an object here and um and then for a request you know this actually is an incoming message from our HTTP package here so that's the interface from HTTP and what we really want to do is because we're going to be basically parsing these cookies anyway it's going to create that sign cookie object and so what we could do is we could just say that this is going to be of type request now we could typically we could actually just pass this in as request but we are going to be using quite a few properties in here and so this might not be best practice to be honest um only because uh the fact that it doesn't actually have all of the properties of requests right and so if we actually wanted to like if we want to look at like request.query it wouldn't exist and that would cause issues and so it might be more correct to kind of just pass it in like this as request so it would just kind of be like this and then we could pass in this as response and so everything that goes on after this we want it basically in the next function so we want it to happen after the cookies have been parsed right and so we're going to parse the cookies and it's then going to basically create our signed cookies object right and so in our function here we can actually look at we can create this variable sign cookies and it's going to be on here which is going to basically be request as request and this is kind of why you know if we really wanted to save a little bit of code or make it look better looking you could make it here but again better practice to not do that because um you know if we actually try to like access you know request.query in here at least it's going to prevent us from doing that right all right so we have signed cookies now and we can say a t is going to be signcookies.at all right and so at is going to basically be our access token uh and this is going to be what we actually want to set in the cookies themselves and so it's also going to be what we're going to be using as our authorization token as well so if so if that doesn't exist if that cookie does not exist right we want to actually look at the headers right and so the headers are basically going to have um well basically typically we would look at headers right in a normal kind of like if you watch my other videos if we weren't on the cookies we look at the headers we look for authorization and then you know a bearer token type format uh but in our case we actually can't set the request headers on websockets and so we need another way of doing this and typically what you would do or at least the way that I've always done it in the past and the way that I recommend doing it is kind of setting a query parameter on your websocket URL and so if not a t what we actually want to do is we want to grab a you know a new URL so cons URL equals and we're going to create this new URL and it's with request.url and so now request.url is of type string so we need to set it as string but again if this is not a URL so what you kind of want to do is you want to say if not at and not not request that URL then you should let's see if this actually works now yeah okay the typing fix that so you want to make sure that request.url exists and you say if not a t and not not request that URL then what we're going to do is we're going to pass in you can actually say WS or WSS the protocol doesn't necessarily matter here um what we're going to be actually looking at is request.headers.host and honestly you could put whatever you wanted here you could even put you know google.com uh we don't really care so much about this we're really only going to be looking at the URL dot searchparams dot get and what we're going to be getting is at right so it's actually going to be looking for a search param called at and basically this is just you know after the question mark you know these are this would be the property and we're looking for the value of that right so in our query string and then we can actually look at if not a t at this point right or sorry this is not what we want to do we actually want to use our valid token if not valid token a t right then what we want to do make sure it's not is we want to call basically unauthorized and we're going to destroy the socket right and so here's essentially all of our authorization code we're looking at the cookies all right if the cookie does not exist and the URL does exist then we want to do is we want to actually try and grab a query param and at that point we're going to pass whatever this value is into the r ballot token function again this might end up being an asynchronous function it wouldn't change anything if it was basically this would just now be an asynchronous function instead of you know a synchronous function and if it is valid then we're going to upgrade to our socket right and we're going to actually establish connection once the connection is established we don't worry about you know our actual tokens or anything being passed up right so we're only really doing our authorization on upgrade right so once the connection is established we validate that every message sent is going to be valid and so again we are only validating once and then the connection is good to go so every message sent after that is now officially a validated client and until you actually uh close the connection it is going to remain you know active and accepting messages so this is actually all we really need for our socket logic right now what we want to do is we're going to kind of simulate logging in and actually setting our cookie and so let's go ahead we're going to delete this function because it's useless we can go ahead and leave this function it's also kind of useless for what we're doing but what we're going to be doing is we're going to kind of copy um let's copy this twice and we're going to create a login oh not double l login and I'll log out route all right so we're going to create login and log out now in our login you can actually see almost these exact same functions in the you know cookies and tokens video uh but we're going to make sure that we check credentials you know encode a token and then what we'd actually do is we would set res dot cookie and we're going to set the at Value and in our case we're just going to be setting it to test but typically again you would actually be setting it to some encoded token and we're going to make sure that we use the HTTP only as well as sign true so it's going to actually sign it with our secret that we passed in and then finally for log out oh and make sure we actually you know send something back so res dot status 200 and then typically you would actually send back the encoded token but in our case you know our TK just equals test and then we're going to be passing in you know the same value right all right so we have our login function and for log out all we're going to be doing is res that clear cookie a t where is that status 200 and then we're just not going to send anything back um and then a lot of times you'd actually store this value in some kind of configuration file you want to make sure that that's essentially a global value somewhere and that's going to be you know our access token more or less right because we are referencing it over here as well so normally you'd have that value stored somewhere so for instance if we stored it in here you know export comps and it would be uh let's just call it a t right and it's going to be a t and [Music] well let's call it a t key right so at Key and in here you would actually let's see in our socket what we'll be doing is we would be importing that so we'd be looking at at key right and then here we would be setting it to a t key and at key right so that way everything's consistent and we know we're not messing anything up as far as that goes right all right so that looks good um and we have our login logout functions let's go ahead and we're going to go into our front end now so let's go ahead and pull up our indexed HTML and we're basically going to just be adding a few buttons in here right and so what we want to do is we basically want to create uh let's see we want to have a login and a log out all right so let's go ahead and just kind of fill these out log in log out and then we want a final one that's going to be basically another way to open a connection but we're going to call it just token connection right so it's going to be open token connection and we can just say you know give it a different ID but basically this is going to be opening a connection relying on cookies and this is going to be opening a connection relying on a token right that's really going to be the only difference between the two and we're going to kind of see how that works so let's go ahead and go into our public app.ts here and what we're going to do is we actually have to grab our other two buttons so we had essentially another open right we can call this one TK open and we're just going to add that and then we have our login and log out right and so let's do we can just kind of copy this one twice and we have login log out log in and log out again right all right so we have all of our buttons now and we uh we can kind of write our login and log out functions real quick so let's just go we're gonna go all the way to the bottom here and we're just going to attach those event listeners so log in dot add event listener right and it's going to be click and it's going to be an async function and we're going to uh for login what we're going to do is we're just going to make a request we're going to do a fetch request so we're going to await Fetch and it's going to be slash little slash API forward slash V1 forward slash user slash login all right and that's basically just defined by our router here the API router and then we have our user routes and so um that's pretty straightforward and we can just check if you know res dot ok then we can show message and we're going to say just logged in you know else let's show message and we're going to say log in error all right and then we're basically going to have almost The Identical thing for log out right so let's just change log out here except it's going to be a different route and these are obviously going to change logged out and we're going to say log out error right all right so we have our login and log out change now uh the only other thing I would say we probably want to change is we're not really keeping track of this WS like we're not setting it to null if we close the connection and so if we want to actually send a message or know that we don't have a website connection we probably want to add an additional thing here so oops wow that was crazy let's say WS if WS at ready state does not equal you know websocket dot open then we're going to assume that we have no websocket connection it's really no active websocket connection because we probably would have at one point it would just be in some state of closing or closed but again we don't want to be sending a message if uh it isn't open right and so this is just an additional safeguard that I think is valuable for this lab I don't think I had it in the template but it is good to have and so I highly recommend that you add this and I probably should add it to the template but I want the code to be the same as you know what we actually coded in the video so again we have this just kind of as an additional check checking that it's open if not we're going to show the message that there is no websocket connection and then the last thing that I kind of want to do is I want to abstract out this WS open because we now have two ways to open a websocket but it's basically the same logic and so I'm not going to obviously copy the code and so what we're going to actually do is we're going to create a function called a knit connection and we're actually going to be passing in an optional argument that is going to be our token right and we're going to be returning a function and that's basically going to be our event listener so we're basically returning this function here and so we can go ahead and kind of just copy everything that's in here we're going to cut it all out and paste it back in here here so and instead of just actually opening up this new websocket we're going to kind of turn this into a temperate template literal wow and we're going to say um you know not TK then it's just an empty string else what we want to do is we want to pass in the actual query string right so we're going to say a t equals TK and so this is going to be the a t value that we're looking for you know in our query parameters and that should satisfy if we init the connection with the correct token that's just satisfy what we need right now typically what you'd have to do to get this token is you'd have to send a request to your auth server and highly likely that your auth server isn't going to be your websocket server or at least I don't recommend that it's the same in our case we're doing the login you know with the same server don't recommend that normally so you know we're not going to actually mimic grabbing the authorization token uh pretend that you know there's another server somewhere you make a fetch request to that authorization server or that auth server and it would return your token and then you could pass the token into this connect init connection and create this websocket connection right so that would be kind of like the order of operations here but what we're going to be doing is instead of this function here we're going to be calling a Net Connection now we're also going to have our wstk open right and this button is going to be adding an event list there but we're going to actually be editing the connection with test right now if we init this with another value we should get an error you know so this would be basically the token that we're getting back from our all server where it is in our case we're just using test uh and this is just for speed things up a little bit but that's more or less all we should need actually so let's go ahead and run this real quick so we're going to npm run Dev and once we got our server listening we can go ahead and pull up localhost 3000 and so I'm going to go ahead and pop open a little console as well and so we can actually see that you know obviously we try and send the message we get no websocket connection uh and if we open a connection we actually get a websocket error right so this is an authorization error right so we don't actually have the right cookies set up we don't have the right token in place but if we actually log in first you can see that we're logged in if I were to check my application now you can see that we have a Cookie in here called at and so we have an encrypted cookie that's HTTP only exactly like how we wanted it um and more or less like what that means is that if we send a message now uh oh we haven't opened the connection sorry we obviously have no website if we open a connection first we actually can establish a connection so we can now send a message and we can see that we sent and received the message right now if we log out all right we've logged out and actually what I forgot to do is we logged out but this connection is actually still open right and so typically what you'd want to do in this case is when you actually have a log out function like this um what you can do is you can actually close your connection right so you can close the connection and then you can actually do the request now a lot of times when you log out you typically will log out and then immediately reroute somewhere else and so I would recommend just closing connections some people say you know you shouldn't close the connection until the logout request is successful because you don't know if you've actually logged out but in my case like a lot of the times logging out is kind of like an event based thing where you just want to kind of clear things instead of actually having to do like handle data or anything like that right and so I would suggest closing the connection immediately for something like this and then handling other possible errors elsewhere uh you know rerouting if there is an error with this right to somewhere where you don't want to go or somewhere else you know in particular but again I would always suggest closing the connection immediately right so if we go ahead and we pull up our thing and kind of do this again right where we try and open a connection we can't we log in first then we open the connection right and then we kind of send a message and then now when we log out we actually close the websocket connection right which is what we want we want to make sure that connection is closed when we log out because now if we try and send the message we get no websocket connection if we're trying to open the connection we get websocket error right so we have no connection right now but if we open a token connection right we're actually logged out so if I keep trying to open this it'll always say error but if I open a token connection we actually get websocket connection established right I can send a message I can send any I can send messages all day long right now I can close the connection or I can log in or log out right if I can close this connection if I try and open the connection obviously it is connection closed now if we change this function to basically only show sorry if we passed in looking for this right we passed in the wrong code right if we pass in extra T in there right so that we would this would be an invalid auth token essentially right now if we try and run this again if we open the token connection you can see that we get a websocket error right so we're actually our authorization check is working because we pass in an invalid token we still get a websocket error right so go ahead and fix this real quick and now when we actually pass in the right token you can see that we have our websocket connection established right we can send our message we can close the connection we can log in open the connection right send the message we're good to go so basically we're simulating two types of login where else we're setting cookies and we have our cookie value right right now we are essentially authorized through cookies and if we log out this would be kind of like making an off call to an all server receiving a token and then opening a connection with that token we now have our websocket connection established and we can now send and receive messages and we're good to go all right so I feel like that was pretty straightforward and easy enough if there's anything that I kind of didn't really make a whole lot of sense with or maybe I messed something up feel free to drop it in the comments below and I'll be happy to explain further also if you guys have any future ideas as far as web sockets go or you know authorization authentication goes drop them in the comments we love hearing from the audience we love making additional videos based off of your feedback so otherwise make sure you subscribe we'll be putting out more videos soon check out our merch store in the link below and we'll see you soon
Info
Channel: Covalence
Views: 10,877
Rating: undefined out of 5
Keywords: Covalence, Programming, Coding, Software Development, learn to code, online coding bootcamp, intro to react, intro to javascript, intro to typescript, node.js, MySQL, .NET, React.js, free web development tutorials, software development bootcamp, web development, javascript, typescript, mern stack, express, become a programmer, how to become a software developer, programming tutorials, become a full stack developer, software careers, websockets, ws, authentication, authorization, cookies, tokens
Id: twNgfrE4ShE
Channel Id: undefined
Length: 26min 10sec (1570 seconds)
Published: Fri Apr 07 2023
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.