In this video you'll be setting up an express middleware function you can use to add authentication
to any request in your application.
We're going to use the same principles we discussed in the last video.
Although the function in this case will check for an incoming authentication token it will verify that
it is a valid Jason web token.
Then it will find the associated user.
Now when we first explore and express middleware in the last one we just defined our middleware functions
right in line inside of index not J S.
This works well for experimentation.
But when creating middleware to be used throughout your app it's best to define it in a separate file
so we can keep things nice and organized.
Now inside of the source directory we have D.B. models and routers.
We're going to create a brand new directory and they're called middleware now.
Middleware is going to store a new file for each piece of middleware we're trying to define it and in
our case we're gonna have a single middleware function for the moment.
The one concerned with authentication right here I can call that something like off dot J S or authentication.
Dot J S in here we're going to set up and define the authentication middleware.
Then we'll actually load it into our routers to put some of the roots behind authentication.
Let's go ahead and get started though by defining the function we'll be working with right here.
We can create a new constant called auth and we are going to set this up as an async function so I can
take advantage of async and wait right here as we saw in the previous video request response.
And next and all we'll do for the moment is just print a little message right here console dot log off
middleware just to make sure it's running and then down below.
I'll call next to allow the associated root handler to run.
Now remember we're defining the function in this file but I want to export it so it can be used elsewhere.
Right here we'll do just that by setting a module dot exports equal to the off function we justify.
Now we can load this in from other files to use the middleware wherever we need to.
Now in the last video we registered all of our middleware in index dot J S when we do this it's going
to be associated and used for every single route in our application with the off middleware.
That's not what we want certain requests like signing up and logging in should not use the off middleware
at all.
So let's see how we can get this done.
What I'm gonna do is comment out the maintenance middleware.
So our application actually works as expected and we're gonna head over to the user router we're gonna
learn how to set up middleware for an individual route to get started.
We are going to need to require the function we created in that separate file.
So right here const off equals I'll be using require starting with a dot dot to get out of the routers
directory then forward slash middleware forward slash off which is the file we defined now that we have
that in place we can add the off middleware to an individual route.
Now the first one is for signing up and the second is for log in the two routes that we don't want to
add authentication to.
But let's go ahead and add it for the third one.
Get forward slash users to add middleware to an individual route.
All we do is pass it in as an argument to the get method before we pass in our route handler.
So right here the root handler is the second argument to get we're gonna go ahead and move it to the
third argument position.
And the second argument is going to be the middleware function to run which in our case is off.
So now when someone makes a get request to forward slash users it's first going to run our middleware
then it'll go ahead and run the root handler.
Now remember it's only ever going to run the root handler if the middleware calls that next function.
So this is how we're going to get access to control how things are working let's go ahead and see this
in action before expanding on the middleware any further.
So right here I'm gonna make a request to get forward slash users from post man.
I'll go ahead and do just that right here.
I'll send it off.
And what do I get.
I get my users back and over inside of Visual Studio code I have the off middleware message printing.
If I was to fire off a different request like log in it would still indeed work and I wouldn't see that
message down below a second time because the log in route does not use that middleware.
So here by adding about six characters of code we were able to add the middleware to a given route and
we'll be able to do that for all of the routes that should require authentication.
Now let's actually talk about what the off function is going to do to make sure the given user is authenticated.
Now the whole authentication process starts with the client taking that authentication token that they
get from signing up or logging in and providing it with the request.
They're trying to perform.
So in this case I have logged into the user several times and I have my authentication tokens showing
up.
Let's go ahead and grab the authentication token that was just created and sent back with the last login
request right here.
I'm going to copy the entire Jason web token everything inside of those quotes.
And once we had that in the clipboard we'll take it over to the request.
We just added the off middleware to that is get forward slash users.
Now to actually provide the authentication token.
Well we're going to do is set up a request header so we can go over to the headers tab in post man.
And this is where we'll be able to set up key value pairs providing additional information to the server.
Now when we work with headers we can provide them as part of the request.
So sending them from the client to the server and we can also have headers sent back as part of the
response.
So the server can send back some headers to the original requester in this case.
We want to set up headers that get sent as part of the request.
We're providing the authentication token to the server and to do this we'll set up the following header.
It is authorization the authorization header is going to have the following value.
It's going to start off with bearer so B E A R E R that is a capital B followed by a space followed
by the token.
So this is no one as a bearer token in which the client provides the token with the request.
They're trying to perform and this is all the client is going to need to do to actually provide the
information necessary to get authenticated.
So now we can go ahead and figure out how to access this information and then validate it from our server.
So over here and off dot J s Let's go ahead and kick things off by emptying the function we had created
and we're going to load two things in we're going to load any Jason web token library so we can validate
the token being provided and we're also going to load in the User model so we can find them in the database
once we've validated the off token.
So right here a concept JWT and I am going to require the Jason Webb token library then down below on
the next line I'll load in the User model.
So const user equals require we're gonna use dot dot to get out of this middleware directory forward
slash models of forward slash user.
Now that we have both of those in place we can start to fill out the function itself and it's all going
to start with a try catch block so we're going to attempt to run some code that validates the user if
the user isn't valid we will have the catch block down below run if they're not authenticated we're
not going to call next we won't let the route handle or run instead we'll just send an error back.
I'll use response dot status to send back a 4 or 1 status code which lets them know they're not authenticated
correctly and I'll also use send to send back some Jason will have an error property with the following
message Please authenticate.
Perfect.
So this is the error handler.
Now the actual process of validating the token is going to require us to do a bit of work the first
thing we want to do is figure out how to get the value for that header request gives us a way to get
this done.
So right here const token will store the actual value and then we use request dot header to access incoming
headers.
We pass to it the name of the header.
We're trying to get access to now in our case that's going to be authorization exactly like we had before
a u t h perfect authorization.
And now we'd be able to do something with it like validate it for the moment.
Let's just go ahead and log it out to make sure we're actually getting the token correctly.
Right here.
I'm gonna save off dot j ust so the server restarts and I'll make that get user's request an additional
time.
This is the request where we're passing that token along over inside of the server.
What do I get in the terminal.
Right here I have the header value.
It starts off with bearer and then down below we have the actual token showing up.
So the next thing we want to do is get the JWT out of that value and we want to go ahead and verify
that it's correct using these same secret we used when we generated it.
Now in order to get the JWT out of the entire header value all we need to do is remove that barrier
portion which allows us to know it's a bearer token.
Right here we can do that by using the string method replace.
So header returns the string token value and we'll gonna use replace to remove the beginning portion.
We provide two strings what we want to replace and what we want to replace it with.
In this case I am going to replace bearer space with nothing.
Essentially removing it.
Now if there is no authorization header header is going to return undefined.
And if we try to access replace of undefined that's going to throw an error.
Now we could use tri catch to catch that but we already are using tri catch which means that if there
is no token provided the code down below will indeed trigger.
Next up we want to make sure that token is actually valid.
So we want to ensure that it was created by our server and that it has an expired.
So right here const decoded this is going to be the decoded payload for the token and we're going to
use JWT dot verify like we've done before we are verifying the token and we're using the exact same
secret we used to generate it.
Now remember the code for generating the token was defined in the user model.
Right here I have the string that I used to make sure to copy the string that you used as they need
to match up exactly.
I'm gonna take it over to the off middleware and paste it in.
Now we'll know if the given token is indeed valid and from there if it is valid we can focus on finding
the user in the database.
Now we embedded the user's I.D. as part of the token.
So that's what we're going to use to actually grab the user from the database remember we have underscore
I.D. as the thing we've added to that payload.
So decoded has the underscore I.D. property right here.
I'm going to create a new constant user and I'm going to go ahead and use await with user dot right
here find and we're gonna use find one as opposed to find a bi I.D. and we'll talk about why in just
a second right here we're going to provide our search criteria and we're going to start by looking for
a user with the following I.D. the I.D. stored on decoded dot underscore I d perfect.
Now the other thing we want to check is that this token is still part of that tokens array when a user
lives out we're going to delete that token.
So we want to make sure it actually exists inside of there to do this.
We're gonna set up another property on this object but with a string property name and we're gonna use
a string property name because we'll be using a special character inside of their value for this property
is going to be tokens dot token.
This is going to look for a user that has a given token value in one of their array items in the tokens
array.
Now what value are we looking for.
We're looking for the value provided we have the token variable up above.
So all this is going to do is find a user with the correct I.D. who has that authentication token still
stored.
If the user logs out that means this token will be valid.
Now we can go ahead and see if we actually found a user.
So right here if there is no user that is definitely a problem and we want to go ahead and make sure
the code down below runs.
So for that I can just throw a new error to trigger that code and I don't even need to provide an error
message.
This alone is enough to trigger catch down below.
Now if this code runs right here that means things went well and we're going to do two things one we're
going to make sure that the root handler runs since the user has proven they're authenticated correctly.
So for us that means calling next.
The other thing we're going to do is give that root handler access to the user that we fetched from
the database we already fetched them and there's no need for the root handlers to have to fetch the
user again as that would just waste resources and time.
We can actually add a property onto request to store this.
And the root handlers will be able to access it later on.
So request dot we can pick a name like user for this.
And what am I going to store there.
I will store the user variable from up above.
Now that we have this in place let's go ahead and test it out.
And don't worry I'll be recapping what we did here in just a few moments.
So what are we going to do.
We're going to run our request over here from post man.
I'm going to fire that off and we're going to see what we get back and what I get back is indeed the
user data which means I must have authenticated correctly.
Let's go ahead and mess this token up.
What I'm going to do is add a an E right up front.
Manipulating the token string.
I'm going to send it off again in this token it should now be invalid.
Let's go ahead and see if that's actually what happens.
I click send I send it off and I get my please authenticate message with my 4 0 1 response.
So only when we provide a valid token are we going to be able to actually access the given endpoint
and this is going to allow us to lock down our data.
Now we still have plenty of routes that are and authenticated but before we go let's turn our attention
back towards the one route that actually has authentication set up.
There's a problem with this request.
And the problem is that it exposes the data for other users.
Now you do have to be authenticated but that's still not something we want to do.
If a user is logged in they shouldn't be able to see the e-mail address of every other user who signed
up for the app.
Now we added this root to experiment with the basic structure of the rest api.
But when it comes to the user's resource this is not something we want to support.
Now we'll still support it for tasks.
You'll be able to fetch multiple tasks but once we add authentication it'll be just tasks that you've
created not every task in the database with users.
There's gonna be no way to fetch other users data.
So this route actually doesn't serve any purpose anymore but we are going to repurpose it for something
that will exist in the final version of our app and that is a way to get your own profile to get the
profile for the currently authenticated user.
The route for this will still be get since we're getting data and it's going to be a forward slash users
forward slash me.
This is going to allow someone to get their own profile and there's no need to provide the I.D. for
your own user as the authentication token has that information embedded.
Now we can go ahead and remove everything we have in the function and all we need to do is send back
that user profile.
Now when we created the off middleware we assigned that to request dot user and we know that this function
is only going to run if the user is actually authenticated which means that right here all we need to
do is use response dot send to send back request dot user.
And there we go.
We now have a route that allows a user to get their profile when they're authenticated.
Let's go ahead and save the program and actually test this out.
So over in man we have the request that's no longer going to exist read users right here in this dot
dot dot menu.
I can rename that.
I'll have it say something like read profile and then up above we'll just change that you are out from
forward slash users to forward slash users forward slash me.
Now if I fire this off instead of getting an array of users back I should just get back an individual
user and that is exactly what's happening down below.
I have my user profile the user who I'm currently logged in at.
So now that we've seen how we can set up end points that have authentication we're going to continue
on adding authentication throughout the application.
Now in this video we just got the barebones setup in place.
We're going to talk a lot more about headers authorization and bearer a little bit later in the class
but for now everything is indeed working.
Let's take a quick moment to recap.
The first thing we did is we set up a middleware function to run for this specific route to the route
that we want to lock down with authentication.
We passed the middleware function in as the second argument.
And the root handler in as the third.
Now the middleware function itself starts by looking for the header that the user is supposed to provide
and then validates that header and it finds the associated user from there.
One of two things happen either we call next.
Letting the root handler run or if they're not authenticated we go ahead and send back an error letting
them know that they're not able to perform the operation that they're trying to perform.
I'm very excited to continue on with authentication.
So let's jump right in to the next video.