41
loading...
This website collects cookies to deliver better user experience
npm i express
npm i bcrypt
npm i jsonwebtoken
npm i mongoose
npm i body-parser
req.body
But first, let's require some helpful modules at the top of our server.js file. JWTs will be used for the login system, but the register route needs access to the User schema and bcrypt as well.findOne
method is on the User model that we imported from our user.js file and that it is awaited because we don't want to have our if statement happen before we check if the username or email is in the database. After confirming that a user is not already in the database, we use bcrypt to hash the password. The second parameter of bcrypt's hash method describes how many rounds the hashing algorithm should perform, so for mine it would go 2^10 or 1024 times. The higher the number, the harder it is for the password to be brute forced but the more processing time is required. Finally, we can create the user in the database by describing their information in the same way that you specified in the user schema in user.js. We then save it using the .save()
method which is asynchronous and can be awaited if you need to do further actions once the database has been updated. One last note about this process is that you should try to keep your res.json() calls consistent for an entire route by having the same keys so that your frontend does not receive undefined
when trying to access properties from a server response. This is why I have "message" as a key in all of my res.json() calls..then
to check if the user exists, and if they don't, we send back a message saying that the username or password is invalid. Pretty simple so far, right? If the user exists, we then validate the password with crypto's compare method which also returns a promise. If this promise resolves, we move on to "signing" the JWT which means that we create the token and send it to the front end. The first parameter of jwt.sign
is a payload which is basically the information that you get when you decode the jwt later on. It's ideal to put any information about the current user here, so the username, id, and email should probably go here, especially if your app has a profile page for the current user. The next parameter is a secret key used for encryption which you should store in your environment variables, and the third parameter is an options object in which I specified how long before a token should expire (86400 seconds is equal to 1 day). You can also specify the encryption algorithm here. Finally, the fourth parameter is a callback which you can use to signal a success to the frontend and send the token to be stored on the client side. We need to prepend "Bearer " to the token because it specifies that we're using token based authentication. The alternatives are Basic and Digest authentication which utilize a username and a secret key instead. .verify()
method which helps us do this.req.user
and set the decoded username and id to req.user.id
and req.user.username
as shown in the code below. decoded
parameter that holds the current user data. Since we set the req.user data below that, the next route that comes will have access to the req.user data as well. Lastly, if the token does not exist or fails to authenticate, you can see that we send {isLoggedIn: false}
back to the client side which will redirect the user (we will use react-router to do this)localStorage.removeItem("token")
), the verifyJWT middleware will fail and thus send a response that has isLoggedIn set to false. If your frontend handles that correctly (which I will discuss how to do in my next article), you can redirect the user to the login page whenever this response is received