The Ultimate guide to JWT client side authentication (Stop Using Local Storage !!!)

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hello my name is cassie franz and thank you so much for checking out this tutorial in this tutorial i want to talk about how to handle jwts effectively and securely on the client side the most popular practice in the industry today is to save your jwt in a cookie or in your local storage i've done this for a couple of years i've done this for a couple of years and i've even taught it i've done this for a couple of years and i have even taught others to do the same but i didn't think it was a big deal until one of the applications i worked on was hacked now this was an xss attack this is an attack in which a malicious person runs malicious code on the client's browser directly attacking your application now there you could do this to get access to your local storage or to your cookies and extract the jwt from there now using this token from your local storage or from the local storage of your customers computer they can pretend to be that customer now this is really risky because the jwts that would be used as sessions or as local storage tokens would be long-lived and the attacker would have a really long time and a lot of access to your jwt so the solution we want to talk about today is a solution that would first of all prevent us from saving our tokens in a place that is risky which is local storage or cookies and secondly implementing another solution that makes sure even if an attacker manages to get hold of a token the assets using that token will expire almost immediately that way we are very very secure and difficult to hack and even in situations when we are hacked the assets of the attacker expires almost immediately so let's get started for this tutorial the first thing we need is a backend so i have a setup project and i will share the link with you in the description and it has an api and clan folder the api folder has a basic server using 10c js and you should definitely check out tensorjs because in just 24 lines of code i was able to get an off server a graphql server with a lot of mutations and queries that automatically set up authentication with jwts and an sqlite database to quickly test things now secondly i set up a client with quit react app in the index.js i mount three routes with react router sign-in register and the dashboard the dashboard is at the home and now if we go to the dashboard if the user is not logged in so if there's no customer then i redirect to the sign-in page and that's what happens right now if i visit the app in the browser i'm redirected to the signing page now the register page has three inputs name email password and we have and on submit here that extracts the values from the form and we would be implementing this functionality so what's the first step for implementing jwt the first step is when a user creates a new account we want to communicate with our backend create a new account for this user and then the backend would respond with a jwt which we would use to automatically log in the customer so i have a snippet that already does this so i'll paste it in here and basically what this does is calls client which is our api client and makes a request and it's the register request and passes the payload which is named email password and then it gets the response the response contains a token and a customer now when we get the token we are going to set the client header authorization to be better and that token now this token is the jw2 that the back end responds with and the customer is the details of the newly registered customer and we set that in memory notice we are not saving the token to local storage notice we are also not persisting into cookies we're just saving it in memory now in memory means that application is almost immune to cross-site scripting attacks because there is no way for the attacker to reach out to our application in memory and get the token and that's really secure now it would definitely lead to a lot of questions which we are going to answer in a little bit so let's go ahead and try to register a user and see what happens now i would register a new user john doe jonatha.com and password now we check out the network and we expect to see a request go out to the server the token set to the header the customer set and the user redirected to the home dashboard so let's create an account and we are redirected to the dashboard that shows us john doe and the email of the locked in user now let me go to the dashboard and as you can see here it gets the customer and displays the name and the email and that's good but let's look at the request from the server for a little bit the first thing we notice is that there is a set cookie in the headers so it makes a post request and if you are not used to graphql don't worry about it it's basically making a post request to a point to an endpoint called register customer now when the server returns the response and this is the response with the customer and the token it also does something it sets a cookie and this cookie is refresh token that's it there and now it also sets some very important properties on this cookie first it expires in about a week's time that's by default we can customize this and then it also has the http only flag and that tells the browser that this cookie should not be accessible via javascript so if you do document the cookie you can see all the other cookies that are on my browser for this particular domain but you wouldn't see the http only cookie that was just set by a server so that's really important you need to have the server set a http only cookie with the refresh token on your browser and it can expire in two years three years it doesn't really matter because we've made sure that number one on the server this refresh cookie only gives access to this account and secondly it does not give access to the rest of the account capabilities it can only be used to request for an access token okay so your server needs to do this now tensei does this really well by default so it automatically sets the cookie for us in the browser now we'll talk about what this means and how we'll use it but now we have a locked in user and we have a cookie set on the browser but this cookie cannot be accessed via javascript only via http which means when we are making a post request to the server or a get request the browser would automatically attach this cookie for the http request but it would never be accessible by client-side javascript so now let's refresh the page and there we have our first problem the user is locked out and that's because the session is not persistent we didn't save it into local storage we didn't save into any cookies except the refresh token which is not accessible via javascript which means we also cannot access the refresh token so how do we fix this now we are going to go to the store and think of this as maybe a redux store or if you're coming from vx it's going to be a viewer store where we store our customer credentials now this is where we have the customer and this is where we should probably be getting the customer from local storage and setting into states or into context so that the whole application can have access but that's not what we are going to do we are going to call the backend and the backend is going to figure out if this user is actually logged in and if the user is logged in then it would return to us a jwt for that user now we are going to call an endpoint called refresh token and i'm just going to replace this with the snippet for that and the endpoint is called refresh token so client. request refresh token and this is called on the use effect hook so as soon as the page mounts it's going to try to refresh the token now this endpoint is going to check the http only cookie that was set on this browser and if it is valid then it is going to generate a jwt for this customer and then return to us and then we can get the token which is a jwt and we can set it as a header on the client that way the user has access and is automatically logged in now in the case where it fails we wouldn't set a customer which means that we would be automatically redirected to the login page so let's try this out i would refresh the page right now and now we are automatically logged in so what happened let's look at the graphql request now if we look at this request that went out it sends request headers now the request headers you can see there is a cookie and this cookie contains a refresh token right here so the refresh token is automatically attached to every request going to our server and that's because it is an http only cookie which we cannot access from the browser but it's sent to the server now which request did we make we made a request to refresh the token and this endpoint or this graphql mutation returns towards the customer returns to us a new jwt and an expires in timestamp now every time the user refreshes the page it would make sure that the user is authenticated by getting a new token from the backend and now the user is locked in which means that the user's token always stays in memory and it is never prone to an attack now what happens when this token expires because right now you can see it expires in 3600 seconds which is about an hour and i wouldn't recommend having a jwt this long i would recommend 10 to 15 minutes so that if an attacker gets your token then it would expire real soon now what we have to do is set a timeout because if the user is using our application for about 15 minutes to 20 minutes then we do not want them to be automatically locked out what we want to do is refresh the token even before they need to and to do that we are going to set a tiny timeout and this timeout will do a silent refresh in the background and i'll paste it right here and what this does is it sets a timeout for the expires in so let's say it expires in one hour it's going to convert this to milliseconds and then remove 500 milliseconds so this is kind of like saying when it is 59 minutes 59 seconds and 500 milliseconds make the api request to refresh the client's token and then it would set the header and set another timeout that way before the token expires it makes another request to get a new valid token and that's what we call a silent refresh the user does not know what's going on but every couple of minutes i recommend 10 to 15 minutes it's going to make that call to refresh the token and which means we do not save the token anywhere in local storage but it's completely in memory and completely secure now what do we do with logout i'm just going to refresh here you can see the user is still logged in but what do we do with logout now i'm a magician so i automatically made a logout button appear here which we are going to use so when the user clicks on this logout button at the moment nothing happens but what we need to do is clear the user session now the session is persisted using a http only refresh token and we can't access that token from the client side which means we can't clear it so we need to call the backend to clear the refresh token and then and then we clear the in-memory token on the front end to do this i'll visit the dashboard and i will paste in the logout snippet this calls remove refresh token endpoint and then pushes the user to the sign-in screen and sets the customer to know which class the session so let's go ahead and try to click on the logout button to see what it does we click on logout and now we are redirected to the sign in screen but let's have a look at the graphql request first thing we notice is that the graphql request headers contains the cookie which is the refresh token on this browser remember it's http only so it's sent to the server and the server does something interesting in the response headers for the servers it sets a cookie to nothing notice it's empty sets the max age of that cookie to zero and the expiry is immediate because the max age is zero so the server since it can send http only cookies to the browser expires that refresh token which means right now if the user visits the dashboard refreshes the page the user is redirected to the sign in screen because our silent refresh or our refresh token endpoint now returns invalid refresh token and that's really good now this is much more secure and improves a lot of security vulnerabilities there are with storing the token in local storage or in cookies all right so i think the only pending thing is the login functionality so i'm just gonna copy the snippet visit the login page and paste it right here and if we log in with john.1 com we are redirected to the dashboard page which means the user can successfully log in and just like the register the login sets the authorization header to bear our token which is the gwt sent from the back end and if we check in the graphql request the login customer also sets a refresh token cookie which is http only on the browser it also sets the customer in the code and pushes the user to the dashboard okay so that's been it but there are two important settings that we have to keep in mind before this can actually work now this example is a little bit trickier because the client side and the server side are running on different domains so if your client side is running on a different domain and your server side is running on an api domain for example then there are some configurations that you need to know the first thing is the client needs to include credentials permitting the client which is the http client permitting the browser to send the cookie from one domain to a completely different domain so if you do not specify credentials include to your http client it could be graphql client it could be xios or fetch whatever you're using then it wouldn't send that cookie and your server wouldn't be aware of it secondly on your backend server you need to allow the backend server receive requests from the other domain that's configuring course and most importantly you also have to say credentials true and this would instruct the back-end to accept credentials from a different domain and also accept requests from a different domain now in case you're wondering how all of this is happening with tensei tensei is using apollo graphql behind the scenes and it's gonna pass all the middleware options directly to the apollo server for you now i really encourage you to check out tensei i think it's a really amazing way to build applications super fast super lightweight super easy to write you can see in 24 lines of javascript which could actually be reduced to 10 lines we were able to get a full-blown graph qr api with authentication refresh tokens access tokens and we can even have more for example if i call verify emails here then we automatically have email verification setup for our authentication i can even call two factor off and this automatically sets up two-factor authentication for all of our registered customers then i can also call roles and permissions and we would have a full-blown roles and permissions system to authorize our operations there's so much that density has to offer and just by providing these tiny configurations we can have full-blown back-end applications in absolutely no time so please check it out also share this video to as many people as you can i really want people to start building more and more secure apps really easily please follow me on twitter like my youtube channel subscribe and also subscribe to my email list so that you can always be updated whenever i release fresh content like this one thank you so much for your time thank you so much for listening to me blab all this while i hope you learned a thing or two and i hope you're gonna start following the best practices for implementing jwt authentication thank you my name has been katie franz see you in the next one
Info
Channel: Kati Frantz
Views: 98,803
Rating: undefined out of 5
Keywords: nodejs, react, jwt, authentication, client-side, local storage, reactjs, single page apps, access tokens, refresh tokens
Id: d2gfJ8UVPDo
Channel Id: undefined
Length: 18min 22sec (1102 seconds)
Published: Sun Nov 22 2020
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.