3.2 Configuring Passport
In this lesson, we’ll install and configure Passport, the NPM package that will handle authentication and authorization for our users’ accounts.
1.Getting Started2 lessons, 03:51
2.Project Setup3 lessons, 20:58
3.Server-Side Code6 lessons, 53:00
4.The Client Side16 lessons, 2:43:53
5.Conclusion1 lesson, 00:29
3.2 Configuring Passport
In our previous lesson, we got started with our server by creating a very simple express application. Now in this lesson, we're going to move onto the next step, which is creating user accounts for our web application. Our server needs some way to authorize users, and so this is what we're going to create here, and to do this we're going to use an npm package called passport. So I'm gonna do an npm install for passport and we're going to install version zero and don't forget to save that to your package.json file. And the passport library uses what's called a strategy, which is basically just a method by which it can log in. So you could use the Facebook strategy for example, if you wanted to allow people to log in with their Facebook account, or Twitter, or Google, or GitHub. Or anything like that. However, we want to allow them to create local accounts that are just for our web application. So that means we need the local strategy. So I'm gonna to do npm install passport-local@1, and we'll install version 1 of this. And again, don't forget to save it to your package.jason file. Finally, we're going to need a database. Not only to store our user accounts here but also but to store chirps once we start created those chirps. And so, what we are going to use is a little mpm package I liked, called local LocallyDB, and we'll install version 0 of that. LocallyDB will allow us to connect to a database almost like a MongoDB database. However, all that data is just stored in a JSON file. So we don't have to worry about setting up or configuring a database server. All right? So now that we have our packages installed, let's come back here to our text editor and I'm going to create a new file in the root directory of our project and I'm going to call it login.js. And this is where we are going to create our user accounts functionality. Let's start by requiring the packages that we just installed. Of course, we'll start with passport, and that package was just called passport. Next we'll create a variable called local strategy which is our passport dash local package, and finally, we'll require our database locallydb. Now the first thing we want to do after that is actually create an instance of this database. And actually, instead of calling this package db, let's call it locallydb, because instead, I wanna create our db variable. And this is going to be a new locallydb and locally D B is going to create a folder which it stores our data in. And so I'll just say within this home directory let's call it data for example, and we could even put a dot at the beginning so it hides the folder. So why don't we do that. That would be cool. All right, so there is our initial database. Now a local EDB database actually has collections just like a Mongo DB database. So we'll create a users collection by doing db.collection and we'll pass it the string users. All right, now that we have all of our packages pulled in here and our database created, we're ready to start configuring passport so it works with our system. So let's start by calling passport.use, and we pass this function a strategy object. So lets create a new local strategy and then this local strategy constructor takes a function of its own as its callback. Now, this function is the function that will be used to log a user into our system or not log them in if the user name and password do not match. So the function that we passed to local strategy takes three parameters. It takes a user name, it take a password, and it take a done function. And now within this function we need to figure out if the username and password that were passed into this function are a matching set of username and password that are actually in our database. If they are, we will get that user object and pass it back using the done function. If they're not, we'll just pass a done back with a false second parameter. So let's do this. In here we'll say user's dot wear, and we can use the wear function to query our database. And so, we'll just ask for where the user name is user name and the password hash Is and now we actually need a way to hash this password. We're actually gonna use nodes crypto library. So let's require that up here. We can say crypto equals require crypto, and now let's create a simple hash function. This can take a password as it's single parameter and then let's return, we'll do crypto, and then we can say .createhash, and we'll create a sha512 has, and then we will update this by passing it the password. And I've just realized I used the wrong argument name here, that should be password. So we update our has with the password text, and then finally we get the digest, and we pass it hex there. As a parameter to get the hex digest, and that will return our hashed password. And so now back down here, where we need this password hash, we can say hash(password). And what this will do is take the password that we've passed in to our strategy function here, and it will hash it, and it will compare that with the value in the database. So this means when we actually get around to storing a user in the database, we will use this same hash function, to hash the password before we store it. So we never actually store plain text passwords. So backing up a little bit here, we have our users collection, .where. We'll search the database for any records that have this username and this password hash, and so then it will return an object with an items array as a property. And so we can say .items and then let's just get the first item out of that array because we know we'll only allow it to ever store one record with a given username. So let's store all that in the user variable. If there's nothing in that items array we'll just get back undefined here. So we can use if there was a user then we'll call done and we'll pas no as the error parameter and we'll pass user as the second parameter, otherwise We'll call done and we'll pass null as the error, and we'll pass false as the user. So this is just saying there was no user. Now we don't wanna say that we got an error, because there was no error. We successfully checked the database and found that there was nobody there. However, in this case, we'll just keep it simple and have these cases here, if the user was found or if the user was not found. So that is our basic login functionality. When a user tries to login their username and password will be passed to our local strategy here, and then if their user object was found, they will be logged in to our web application. However, remember that, http is a stateless protocol which means that there's no way to keep a user logged in over multiple requests. Instead what will happen is a cookie will be passed to the server and that cookie will come back in the headers of the HTTP requests. And so then passport here on the server side, basically, will keep track of those individual cookie IDs, and match them up with our users here on the server. However, for it to do that we need a way to serialize and deserialize our users. Basically, this means we need to be able to convert our complex user object down to a single value, usually a number or some other atomic form of data. And so for this we're going to use the passport serialize user and deserialize user methods. So, we'll say passport.serializeUser, and this takes a function as a parameter, and this function will get passed to user object and a done method. And so then in here what we need to do is convert our user object here to some smaller value that basically will reference our user, and in our case, that's just the user.cid property or client id. So user.cid is the unique id that locally db will give each one of our records. So what we can do is just call done here and we pass null as our error parameter, and then we pass the user.cid back out of serializeUser, and that is the serialized form of our user. The opposite of this, of course, is passport.deserializeUser. This will take that serialized form. So, in our case, that's just the id, and of course, it will also take the done method. And so in here, what we want to do is use users which is our collections and we can say .get and we can pass it that ID. And that is how we will get the user out of the database, and so let's again return this with done. So this is our serialized and deserialized methods. We can serialize our user by just passing out its id and then we get that id back and we can use that to quote convert our user back into the full object. So, this is all we need to do to configure passport. So, in this lesson we have set up passport as our user account management system on our server side. In the next lesson, we're going to look at a couple of pieces of middleware that we need to allow our users to stay logged in over the course of multiple requests.