Golang API Authentication using JWT Tokens

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
in this tutorial we'll build an authentication system using go before building the app i would like to remind you that this video is meant to be combined with other videos so if you want to use go with angular react next gs view nox.js or the weld check the links in the description also make sure to check scalablescript.com now let's build the app now let's download and install go before i start make sure to know the basics of go so if you are a total beginner make sure to watch a tutorial about go basics first so with that being said let's get started click download go and download the right version for your machine also make sure to download mysql download the mysql community server and mysql workbench also the go framework that we will be using is go fiber so the fiber framework fiber is a framework inspired by express.js so if you know express.js it it will be easier for you to learn fiber so i'll copy this code and in my project here which is an empty folder i'll create a go file main that go i'll call a package main and i'll create a function so paste the code actually so before i run this up first make sure to get this package so to get this package i already got it from my machine but if you don't have it you should run this command go get go fiber and this will install it in your machine also make sure to configure your go path i will use the version one here because the version 2 throws an error for some reason and we will listen to port 8000 to round this up run go run main.go and fiber will run on port 8000 let's go to port 8000 localhost port 8000 hello world so this is our first go up now let's connect with our database so i'll create a connection to my local database here to mysql so the user is root password is root root and the database is youtube go out so this is my local database which is empty now let's connect with this database to connect with the database we will be using gorm so let's copy this command here go get to install gorm i'll close the server and install this also make sure to install also the driver i won't be using sqlite but i will be using mysql so the driver is mysql so with this we can connect with gorm so here i will import so i can have multiple imports here if i use the brackets and here we need gorm that io slash gorm and also gorm.io slash driver mysql we need those two now let's connect with the database so we have a connection and an errors because go returns can return multiple variables gorm open mysql open we need a string inside which i will add it later and the other parameter is gorm config so this is a connection if an error happens so if error is not nil we need we need to panic so could not connect to the database so panic will stop our app if an error happens now the connection for the moment we won't be using it so i will put an underscore there and if we don't panic here it means that the connection is successful so let's round up so we panicked because i forgot to add the dns here so let's do that so my user is root then i need to pass a password which is root route and then i put a net here and now we need the database youtube go out so this is our local database connection now let's run the app again and now we can see that fiber is running it means that we successfully connected with the database now let's restructure the folders so create a folder here database one folder controllers and we need the routes and that's it for the moment so first let's create the database file so we need here to add the connection connection that go also the package is database so usually the package name is the name of the directory so i'll cut this code go to connection.go and here i'll create a function i'll call it connect and i'll paste this code so we need also to import the driver so driver mysql and we will be using this function here in main.gov so first let's import the database so to import it we have to use dot slash database so we import the directory and to use the function we use the package first connect and this won't change anything now let's add the route so create here go file routes i'll create a function setup and inside i will cut this code and i will put it here so we need up here so the app should be passed as a property here so up is a star fiber up and uh let's pass up here so we need to import also the routes in the routes we'll set up the routes and we will pass the up inside so we have we are done with this also now we need this function so this function should be added in the controller so let's create a go file i'll call it house controller here i'll create a function hello and this function so i will paste this function first and i will name it here hello and now let's use this function let's go to the routes and here we need to import the controllers and to call the function we have to call here controllers hello just like this and now let's run our app and this will return the same so we restructured our files and now let's create the register function so i will rename this to register and in the routes this will be the register function and this will be a post request to api slash register i'll stop the server for the moment and now let's go to the register function and for the moment let's return what the data we will send with the post request so to get the data from the post request i'll declare a variable data here which will be a map string string so this is similar to an array with a string as a key and string as a value so to pass the data we have to call a function c body parser and will pass the data as a reference this way we will get all the request data that we will send this returns an error so we should handle there there are two ways to end the layer one is to add an if condition here if error is not nil when we return the error or an even shorter way which is uh i will add the if condition here and i will add an exclamation here and this looks shorter and cleaner now we got we handle the error we got the data and now let's return see json the data to see what we send so to see the data that we sent first make sure to install postman already did it so now let's send a post request to http localhost port 8000 api register this is a post request and what we want to send is a row request so we will send the name name email aaa.com and the password which will be 1 send so i didn't start the server so we returned exactly what we sent so if i change this to a this will change now we got the data now we have to store this data in the database so let's create a user table in our database to do that we have to create a directory now models and inside this directory i'll create a go file called user and let's create a struct for the user so structs are similar to classes in other languages so type user struct and this user will have an id as an unsigned integer a name as a string an email as a string and a password as a string so this is our user struct now let's create a migration to create a table in our database so let's use the connection for our database here so get the connection and to migrate we have an option here connection auto migrate so let's import the models models and we need to auto migrate the user so we add and here models user with this we can auto-migrate the users let's refresh here we don't have any tables and if i restart the server we can see a users table was created so we have this table with all the fields that we need so we can add also extra configuration for example i want this email to be unique so i add here gorm uniq with this this will make the email unique if i restart the server refresh and as we can see the email was generated unique so gorm is a pretty powerful library now let's create the user here so first let's create a user variable which is equal so first let's import the models here which is equal to models user and we need to pass the name which is data name like this we need to pass the email which is data email and we need to pass a password but the password we won't set the password directly like this because we need to hash the password so let's get a package to hash our password to search for go packages go to go.dev and click discover packages here we need a package called bcrypt and this is a package that we want copy the link here so we can install it so go get be crypt so i already did it and now we can add here bcrypt now let's use it so let's create a variable password and we return also an error which i won't handle it is equal to bcrypt generate from password and we need to pass our password so data password but this won't accept a string so what we need to do here is to convert these two in a slice of bytes so bite like this and the other parameter is a cost which i will put 14 here so the this is how we generate a password and we need to make it as a byte array and this new password can be assigned here the problem is that this password is a byte array also so how do we convert it the best way is to make this password also a byte array like this so with this we can use this hashed password but also we need to auto migrate to the database so for the moment i will return the user here because every variable needs to be used and let's restart the server to see the changes here actually we won't see any changes because the byte array is you it will be still returned as a long text here so everything will work fine now if we send the request again like we did before we will see that the password is hashed and also we return an id here which is zero so we haven't assigned that id in the user model if we don't assign anything it will initialize it 0 for numbers and empty strings for strings so now let's insert this user to the database and we have to get this variable here so how do do we share this variable from this folder to the out controller we have to create a global variable right now where db is a pointer to gorm db and we have to assign it with this variable here so db is equal to the connection so these two pointers are referencing the same variable which is the database connection now we use this variable in our controller so let's get the database and to get the variable we have to use database db so with this we got this variable so the connection and we have to create now and we will pass the user as a reference like this so with this we can insert this user to the database let's try it send a request so this won't create because i forgot to restart the server send it again and now as we can see the id is one so we successfully inserted the user in the database let's see so this is our generated user so our user is created now let's login with this user so let's create a function login this will have the same parameters and let's add it also to the routes so this will post to api slash login and the function is controllers login so we added this now let's make the login so we will get the data like the register function so we will send here an email and a password so by the email we want to get the user with that email so first let's get a variable user as a models user and now we need to call the database db where email is equal to question mark and the email value is data email and we want to get the first result and we want to assign it to this user variable so with this we will get the user based on the email if the user id is equal to zero this means that we haven't found the user so we have to set the status to fiber status not found 404 basically and we have to return here see json fiber map message user not found so if we don't find the user we return status not found and we return this message so fiber map is basically a map with a string and interface so we can put anything there if we got the user then we have to compare the password so to compare the password we have another function from bcrypt which is compare and hash password so the first parameter is the user password which is a hashed value and the second parameter is a byte so we have to convert it also to bytes of the password that we have so data password this returns an error and if an error happens so let's make it shorter so error is not nil here then we send the status so status fiber status bad request and we return c json fiber map message incorrect password so if we get an error here it means that the password is not correct if we go here it means that we successfully send the right email we retrieve the user and we got the right password so for the moment i will return see json the user and let's see if this works so i'll copy this url i'll paste it here and this will be login let's send a post request let's send the body so this will be an email a at a.com and the password is what is the password one so for the moment i'll send the wrong email so did i restart the server user not found so if i put the wrong email it means the user is not found if i put the wrong password incorrect password if i put the right one then we retrieve the user so we successfully retrieve the user here but we want to return a jwt token to return a jwt token we need to install another package jwt and this is a package that we want to use so let's copy the url and install it here go get this package i already have it so i can use here on top and now let's create a jwt token so first we need the claims variable which is equal to this package jwt new with claims so this is a function we need a method which we get it from jwt sign in method hs hs2245 so there are a lot of methods but i will use this hs256 and the second parameter is jwt standard claims and inside we will pass an issuer the issuer is our user so what we want to pass here is the user id unfortunately the user id is not a string so this accepts a string so let's convert the user id to a string so first we have to import here str conf and this can convert this to a string so we use str conf we use this function which i cannot pronounce it and this accepts an ins so user id is you in so this user id cannot be sent like this but we have to convert this to an int so like this we converted the user id to a string so this is claims and we need an expiry expiry set so let's import also time here and when we want to expire this token so we have to pass time now we need to add time hour times 24 so this means is one day and this needs to be converted to unix time so this is our claims so it will expire after 24 hours so now let's create a token and we will get also an error is equal to claims sine string and here we need to pass a byte array of secret so this secret is a secret key that we need to store it in our app so create a constant variable here on top so const secret key and this secret key should be stored in our app and now let's handle the error so if the error is not nil we return the error or we return a better message so i will do it like this we return internal server error and the message is could not log in so we got this now let's return the token and let's see it so let's login again so let's restart the server send a request and as we can see this is a token that we generated now we don't want to return it like this we want to store it in cookies so let's create a cookie is equal to fiber cookie so to create a cookie we need a name i'll name it jwt value the value is the token itself expires so let's copy this part here and this needs not a unix time this needs a time like this and the last one is http only it's important to add http only here because the front end cannot access this cookie so this cookie is meant only to be stored in the front end and stay and send it but the front end doesn't need to access it and to save it we need to add here c cookie cookie select this as a reference and that's it so in the end we can return fiber map message success because we don't want to return the cookie the front end will only have the cookie and nothing more so it won't be able to access it or use it so this is not enough we need to add here on main another configuration so first our front end will have course issues so we need to use up use we need to use course new so don't forget also to import this url here so course problems are the problems that our end will run on port 8000 and the front end will run on different port so if we don't add this uh our browser won't allow the request and it will draw an error if we add this then it will ignore that and we will have the request still we need also one configuration which is course config allow credentials to true so this is really important and with this the front end can get the cookie that we sent and uh it can send it back so this is really important if we want to authenticate using http only cookies so with this let's test it we don't have any cookies and let's send the request so i forgot again to restart the server so message is success but we see here we have a cookie jwt which is http only so we need to use this cookie now to retrieve the logged in user so let's do it now function user i will copy this part and i will add this to the route so this is a get request api slash user and controllers user let's go to the functional and what do we want to do with this function first we have to get the cookie so the cookie is cookie is equal to c cookies and we need the name which is jwd with this we got the cookie now let's retrieve the token so the token and an error are equal to jwd parse with claims so this function accepts first the cookie because the cookie is a string right now we need the claims the claims are gwt standard claims so we need to pass it with reference and the third parameter is a function which accepts a token and the jwd token is a reference and this will return an interface and an error so inside this function we need to return the secret key that we generated here so we have to return a byte array of the secret key and the error is nailed so we don't want to return an error and that's it so if the error is not nil then we want to return i'll copy this paste it here fiber status unauthorized and the message is unauthenticated so if this returns an error it means that the user is not logged in and now we got the token let's get the claims from the token so claims are equal to token claims and let's return them c json claims so let's test this function and i'll copy this url paste it here and this is a get request to user send a request and as we can see we have an expiry time and also an issuer so this is the idea of our user so we got the issuer here and now let's retrieve the uh id but there is a problem claims has only a valid function it doesn't have an issuer function why is that the case because this claims is is an interface that has only a valid function what do we want is to return a standard claims and this has our issue that we want so how do we convert these claims to a standard claims to convert it we have to use dot parenthesis and this will be converted to gwt standard claims so this is how we convert one type to another and now these claims will have the issuer that we want so now let's use this issuer in order to retrieve the user so let's first create a variable user is a type of models user and now let's query the database database db where id is equal to question mark and the id is claims issuer the first result is our user and in the end we want to return the user let's see so let's restart the server so we got an error so as we can see we converted this to a standard claims but this needs to be a pointer of standard claims let's restart again the server and we successfully retrieve the user so with this we don't send anything we only send the cookies and we treat the user i forgot to mention that if we open a new tab the cookie will be preserved that's why we retrieve the user here so we got the user and one thing before we log out i would like to change the format here of the attributes here so first i don't want to show the password and second i want this to be lowercase so how do i do this let's go to the user here we can add some configuration how the json will return so this id will return like this the name will return like this email we can add it here like this so this can support multiple configurations and the password we put a minus here which means that we don't want to return the password with this let's restart the server send requests again and this is our user so name email all lowercase and the password is not returned now let's add the last function which is logout now let's copy this part and to log out now we have to remove the cookie that we just created here so how do we remove cookies to remove cookies is really strange because we don't actually remove it cookie to remove cookies we create another cookie and we set the expiry time in the past so let's create this cookie the name will be jwt the value will be an empty string the expiry so this is the part that we will remove our cookie so we set the expiry time to now and we will add here a time which is time hour with a minus so this cookie expired one hour ago and http only is equal to true so this is how we remove cookies there is no way to remove the cookies in the browser just we set the expiry time in the past so with this the cookie will be removed we have to set the cookie and to the response and let's return the response so return c json fiber map message success and that's it so let's add it to the routes logout logout so with this we completed the logout function let's send so first let's restart the server let's copy the url here paste it here this is logout and we need to send a post request so before i delete the cookie we have the cookie here so we retrieve the user and let's send a post request to the logout method not allowed so this is a post request let's restart send it again and we have message success and the cookie is removed here so if we send the request to the user now we get unauthenticated because we don't have the cookie if we log in again we generate another cookie then we retrieve the user so this is how authentication works in golang thank you for watching this video and make sure to like and subscribe
Info
Channel: Scalable Scripts
Views: 27,575
Rating: undefined out of 5
Keywords:
Id: X9WULjvgqTY
Channel Id: undefined
Length: 43min 20sec (2600 seconds)
Published: Mon Feb 22 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.