Now that we have understood passport and how passport adds
in a simple authentication middleware for our NodeJS application,
and provides a flexible easy to configure
way and provides various strategies for user authentication,
let's go on a journey with our passport.
To get started on this exercise,
as the first step let's install passport,
passport-local and passport-local-mongoose node modules into our confusion server.
So at the prompt type npm instal_passport,
passport-local,
passport local-mongoose mnus minus save and install these three modules.
As you can see at the moment we are starting with passport 0.4.0,
passport-local 1.0.0 and passport-local-mongoose 5.0.1 versions in this course.
Now that we have installed passport, passport-local, and passport-local-mongoose,
let's go to the confusion server and go to the user.js file.
We will update the user schema and model to use the passport-local-mongoose.
To do that, in here we'll say
var passportLocalMongoose
require passport-local-mongoose.
So this we will install as
the mongoose plugin in our application and we can remove the username and
password because these would be automatically added in by
the passport-local-mongoose plugin here and
to use that as a plugin in our mongoose schema and model.
We'll say user plug in and passport-local-mongoose.
So, this will automatically as I said adding support for
username and hashed storage of the password using
the hash and salt and adding
additional methods on the user schema
and the model which are useful for passport authentication.
So once we have completed updating the user.js file then in our project folder,
we'll create a new file and name it as authenticate.js.
In the authentic.js file,
let me import passport.
So we'll say require passport and we're going to
use this file to store the authentication strategies that we will configure.
So we'll say var. LocalStrategy require passport-local,
so the passport local module exports a strategy that we can use for our application.
So we'll say passport-local.Strategy
and then we will import user from models user.
Let's now configure the passport with the new local strategy
and then we will export this from this file because this is going to be a node module.
So we'll say exports.local and we'll say passport and you
can see that the passport supports the various methods
here so we'll say passport use and say
new LocalStrategy and then this is where
the functions that are supported by the passport-local-mongoose comes to our help.
So the local strategy will need to be supplied with the verify function.
Inside this function we will verify the user.
This verify function will be called with the username and password that
passport will extract from our incoming request.
Now in the incoming request for the LocalStrategy the username and password
should be supplied in the body of the message in the form of a Json string.
Again because we are doing body-parser so that'll be
added into the body of the message and then from there passport
we'll retrieve that and then use that and supply the username and password
as parameters to the verify function that we will supply to the LocalStrategy.
Since we are using passport mongoose plugin,
the mongoose plugin itself adds this function called user.authenticate.
So it adds this method to the user schema and the model.
We're going to supply that as the function
that will provide the authentication for the LocalStrategy.
Now if you are not using
passport-local-mongoose when you set up a mongoose plugin that we have done,
if you're not using that,
then you need to write your own user authentication function here.
In the lecture earlier,
I had shown you a simple user authentication function
that can be used here but the one that is
supplied by the passport-local-mongoose module is more
comprehensive and so that is what we will make use of in our application.
Also since we are still using sessions to track users in our application,
we need to serialize and deserialize the user.
So this basically takes the user information.
Now recall that the passport authenticate will mount the req.user or the user property to
the request message and so
that user information will be serialized and deserialized realized by using
this saying serialize user and passport deserialize user.
Also we'll say user deserialize user.
These two functions they serialize user and deserialize user are provided on
the user schema and model by the use of the passport-local-mongoose plugin here.
So this will take care of whatever it is required for
our support for sessions in passport.
So once we have completed this update to the authenticate.js file,
this file will required wherever it is needed for us to use in our authentication.
Next going to the users.js file,
in the users.js file,
we will first import passport.
So we'll say var passport require passport.
Then, because we are using the passport local mongoose plugin,
the mongoose plugin itself supplies some metrics that are
useful for us to use in the sign-up process and in the login process.
So going down to the router post here,
the mongoose plugin provides us with a method called register,
on the user schema and model.
So we'll say user register and this will be turned into saying new user.
This new user is the first parameter that the register takes
and the second parameter is the req body password.
So the password which comes in as a second parameter in the body of the message.
So recall that the username and password are passed
in when you sign up in the body of the message.
Now, in this case,
this will result in a call back function supplying error
and the user as the two callback values here and unfortunately,
this then doesn't work in this case.
So I will have to cut this out from here and then
instead handle that inside this callback method here.
So, let me just indent this,
so that it's more easier to see the code here.
So I'll say, user register and the first parameter is
a new user created with
the username supply here and the second parameter is the password,
and then the resulting is this callback function that'll call,
we will say error user here.
In this case, we have to edit the code a little bit here.
So in the first part,
we'll say if error,
then they will have to explicitly send back the reply.
So, I'm just going to copy these two here.
So we'll say, if error,
then res status code,
we will set this to 500 and set header content type and then,
we'll set res json and then error, error.
So we'll construct a json object with the error as
the value for the error property in there and then send this back.
So this is how you would handle the error in this case.
Otherwise, what we do here is that we'll
say passport authenticate local.
So if we're going to use passport to authenticate the user again.
So we'll say passport authenticate local.
To ensure that the user registration was successful.
we'll try to authenticate the same user that we just registered and
here we'll say req res and this
will return as a third value that function inside which,
we're going to send back the reply to our client.
So we'll say. Let me remove this and then add it in here.
We can now remove this then,
because this then is not necessary for us and this is the closing of the user register.
In the else part,
we will do passport authenticate local.
Look at the syntax here.
So this is passport authenticate local and then following that,
we have to call this function here that the parameters req,
res and that the third one being a callback function here.
So this is the way this is implemented because passport expects you to do it this way.
In here, we'll set req res status code is 200,
set header content application json and then we'll
res json status registration successful and we'll not pass the user value here.
Instead, what I will do is I will
set a flag called success here to true here.
Now this way, on our client side when this json is received,
the client can simply extract the success property and then check to see if it is true
or not to quickly check if the registration was successful or not.
So this is how we will handle the user registration process here.
So notice how the code has significantly simplified.
If the user did not register properly,
then this will send back an error appropriately and also the authentication will fail.
So both cases, you'll catch the situation when the user authentication fails.
Now, the login process itself also gets significantly simplified.
So, we don't need to do all this in the login route here.
So I'm going to remove all this code and this login route becomes simplified here.
Now for the login route- for the router post when we do it here,
here also we expect the username and password to be included
in the body of the post message that is coming her.
Unlike the earlier case where we were including this in the authorization header,
here we expect this to be included in the body of the incoming post message.
So to authenticate, we'll simply say passport authenticate and we'll say local here.
So this will be the second call here.
So this is the second middleware here that we're going to cut.
So when the router post comes in on the login endpoint,
we will first call the passport authenticate local.
If this is successful then this will come
in and the next function that follows will be executed.
If there is any error in the authentication,
this passport authenticate local will automatically
send back a reply to the client about the failure of the authentication.
So that is already taken care of.
So notice how the code in the login process gets significantly simplified.
So, if this goes through successfully,
I only need to check for the req and res and in here what I will do
is I will simply send back a message to the client side with this information in here.
We'll say res status code 200,
res set header content type application json and res json success true status.
We'll say, you are successfully logged in.
That's it. This is the change that we are going to make to the users.js file.
So notice how, because of the user passport,
both the sign up process and the login process,
the code has significantly simplified in this case.
Now we will move on to update app.js file going to app.js now.
In app.js right up here
we will input passport.
Then, we will import
the authenticate module that we just implemented.
We will say var authenticate and in the app.js file down below here after session,
we add app.use(passport.initialize),
and app.use(.session).
If the user is logged in,
then what happens is that when the session is initiated again,
you recall that when you log in here,
you will be logging in here,
and a call to the passport authenticate local,
when this is done at the login stage,
the passport authenticate local will
automatically add the user property to the request message.
So, it'll add req.user and then,
the passport session that we have done here will automatically
serialize that user information and then store it in the session.
So, and subsequently, whenever
a incoming request comes in from the client side
with the session cookie already in place,
then this will automatically load the req.user onto the incoming request.
So, that is how the passport session itself is organized.
So, once this is done,
even our authentication code will become lot more simpler here.
So, in the authentication code,
we will simply say, if req.user.
So, the req.user will be loaded in by the passport session middleware automatically,
and so we'll say req.user.
If not req.user we'll say var err, new error,
you're not authenticated, and all these messages here.
Otherwise, see the else part also now gets simplified.
We'll say else next.
So, your authentication code becomes lot more simpler because if req.user is not present,
then that means that the authentication has not been done correctly so,
that's why you indicate the error.
Otherwise, you are authenticated.
If req.user is present,
that means the passport has done the authentication and the
req.user user is loaded on to the request message,
and so you can just go on further down.
So, that's the change that we need to make to app.js.
Let's save all the changes and then look at the application in Postman.
Once you save all the changes, restart your server.
If your server is running,
stop it, and then restart your server.
Let me start my server.
Once the server is up and running,
let's go to Postman and do a few request.
Going to Postman, let me now try to register a new user
by doing a post on the users sign up endpoint.
When the registration is posted,
you see that in the body of the reply message it says,
success true, and status registration successful.
So, the user has been registered successfully on the client side.
So, now, let me do a login of the user.
So, we'll say, "Login," and still supply
the username and password in the body of the message here.
So, when I click on the "Send",
you will immediately notice that at the bottom,
it says, success, true, and status,
you're logged in and then in the header itself,
you would see a set-cookie coming in because we are setting up the session,
and then you see the cookie in place there.
When you click on the cookies,
you see the session ID in place right there.
So, now we are successfully logged in.
Let's send a request to the Get localhost: 3000 dishes endpoint.
You see that your request went in successfully and then a reply was sent.
Of course, at this moment,
my database is empty so that's why it sends back an empty array
from the server site when I ask for localhost:3000/dishes.
This is perfectly fine.
Let me now log out the user.
So, when I log out the user, now,
you will notice that the user has been logged out and when you click on the cookies,
you will notice that, that cookie for localhost is gone already.
So, now, if you try to do a get on the localhost:dishes,
you see that the reply says,
you are not authenticated.
Let's sign in one more time by doing a post on the users login,
and then, you see that we can successfully login at this point.
You also notice that,
that new cookie has been set up here.
Then, if we do a get on the localhost:dishes here,
now, this will be successful.
Since we are using passport-local mongoose as the mongoose plugin,
let's also go and check our MongoDB server to see how
the user's information is actually stored in our MongoDB.
So, in your terminal,
you can open the Mongo ripple,
so let's say Mongo at the terminal and then connect to our MongoDB server,
and then say use conFusion.
Then we'll say db.users.find().pretty() and then print out the user's information.
So, when you print out the user's information as you see here,
there is one user that we have registered earlier.
So, you'll see that the user's record contains the object ID and then,
the username down below here,
and the admin flag which is false and then,
also notice that instead of storing the password itself what the Mongos
passport-local mongoose plugin does is it stores
its salt value here and a hash value here.
Now, what Mongo's plugin does is that it will use the salt as a way of
encrypting the password and install the hashed password in this hash field here.
So, when you try to log in,
it will apply the same transformation to the incoming password,
and then try to match it with this hash value that is stored here.
So, you can see that in the database itself,
the password is not directly stored inside
the hashed value of the password which is hashed using this salt key here,
that we see here,
is stored in the record there.
So, that is how the passport-local Mongoose plugin enables us
to store the user information within our database.
With this quick understanding of how passport, passport-local,
and passport-local-Mongoose help us to simplify
the local strategy for username and password in our application.
We complete this exercise.
This is a good time for you to do a Git commit with the message passport.