‫Let's now continue writing
‫our protect middleware function.
‫So in the last lecture, we read the token
‫from the authorization header
‫and then checked if the token actually exists.
‫So right here.
‫And next up, we have the verification step for the token.
‫And I hope you remember that in this step,
‫we verify if someone manipulated the data
‫or also if the token has already expired.
‫So we already used, from the JSON web token package,
‫the assign function function,
‫and now we're gonna use the verify function.
‫So just like before, jwt.verify,
‫and then in there, as you can imagine, we pass the token
‫so that the algorithm can read the payload
‫and then remember that this step also needs the secret.
‫So basically, in order to create the test signature.
‫So that secret is process.env.JWT_SECRET.
‫Remember that?
‫Now, as a third argument,
‫this function actually requires a callback function.
‫So this callback is then gonna run
‫as soon as the verification has been completed.
‫So you see that this verify here
‫is actually an asynchronous function.
‫So it will verify a token, and then after that,
‫when it's done,
‫it will then call the callback function that we can specify.
‫Now, we've been working with promises all the time,
‫and I don't really want to break that pattern here.
‫And so, we are actually going to promisifying this function.
‫So basically, to make it return a promise.
‫And so that way, we can then use async await
‫just like any other async function that we've been using.
‫So in order to do that,
‫Node actually has a built-in promisify function.
‫All we need to do in order to use it
‫is to require the built-in util module.
‫So let's do that right at the top, actually.
‫So that will create an object called util, require...
‫All right, so that stands for utility.
‫That's not what I wanted.
‫So that stands for utility.
‫And then on there, we are going to use the promisify method.
‫But since we're only going to use that one method,
‫we can actually do it easier.
‫So instead of doing this,
‫we can simply destructure that object
‫and take promisify directly from there.
‫So again, this is just using ES6 destructuring.
‫Okay, so and now it's very easy to use.
‫All we have to do is to actually call promisify.
‫So promisify, and then pass the function in there.
‫And so now, all this here is a function
‫that we need to call,
‫which will then return a promise.
‫So then here, we actually call the function.
‫And this will then return a promise,
‫and so we can await it and store the result into a variable.
‫So that result value of the promise
‫will actually be the decoded data,
‫so the decoded payload from this JSON web token.
‫So let me call it decoded here.
‫All right.
‫And we can do await because we actually already said
‫that it's an asynchronous function.
‫And now, just to see that it actually works,
‫let's log this decoded data to the console as well.
‫And actually, we can remove this console.log off the token.
‫That one we no longer need.
‫So let's try to send this request again, and yeah,
‫but this time actually turning on this authorization header
‫so that we send a JSON web token along with the request.
‫So that sent it.
‫And now, indeed, we get access to the data,
‫and so therefore, we now have access to the protected route.
‫Okay?
‫But what I wanted to see is this decoded object here.
‫And so this here should be the user ID.
‫So let's take a look at that in Postman again.
‫So 62a42.
‫And so, indeed, well, where do we have that?
‫Let's take a look at Compass.
‫And indeed, the ID of this user is this 62a42.
‫And so that means that we actually have
‫our correct payload here.
‫So basically, the correct user ID.
‫We then also have the timestamp of the creation date
‫and of the expiration date of the token, as well.
‫So this is working.
‫But now let's actually try to manipulate the payload
‫of this token.
‫So let's copy it here again.
‫But then I'm going to the JWT debugger.
‫So again, at jwt.io.
‫So let's take this away.
‫And now what I'm going to do is to change some data here
‫and that will then change the encoded token here,
‫which I can then go ahead and copy.
‫So let's simply replace,
‫actually, I will just replace these two numbers here
‫with something different.
‫And so, as you see, this changed the token over here.
‫And so now, I will actually try to get access
‫to that protected route
‫using this manipulated JSON web token.
‫Okay, make sense?
‫So just to see if it's working correctly.
‫So I'm copying this one here now
‫and pasting this other different one.
‫And so, if I now send this request, then we get an error.
‫So, great.
‫So, we see the error name is JsonWebTokenError,
‫and we have an invalid signature.
‫So, great.
‫That's exactly what we were looking for.
‫So that is one of the two errors that can occur.
‫The other one is that the token has already expired.
‫So this one is called JsonWebTokenError,
‫and so actually, let's go ahead and handle this error now.
‫And the way we could do it
‫is to add a try-catch block right here.
‫Right?
‫So right after doing this code,
‫we could introduce a try block,
‫and then in the catch, we would then create errors
‫that would be sent to the client.
‫Now, instead of doing it that way,
‫I actually want to use our global error-handling middleware
‫in order to do that for us.
‫So we don't like to do error handling right here
‫in our middleware function.
‫Instead, we usually delegate it to the error controller.
‫And so, let's do that exact same thing here.
‫So error controller.
‫And then it's actually the exact same thing
‫as we have with our other errors here.
‫So for example, the validation error coming from Mongoose,
‫so from another library.
‫And now, this error is actually coming from another library
‫and it also has its own name.
‫So let's get that.
‫And it's JsonWebTokenError.
‫All right.
‫And so, let's do very similar here.
‫So if
‫.name is this,
‫then error should be equal to handle error.
‫Okay.
‫So let's go ahead and create this function, actually,
‫somewhere up here.
‫And this one is actually extremely simple.
‫All it does is to take an error
‫and then return a new AppError.
‫Okay?
‫So in this ES6 arrow function, as I hope you know,
‫we can write these one-liners
‫where we don't even have to specify the curly braces
‫and neither the return keyword.
‫So this will automatically and implicitly return
‫whatever we put here.
‫Right?
‫And so, what we want to say here is simply,
‫invalid token,
‫please log in again.
‫And then, the error code, just like before,
‫is a 401 for Unauthorized.
‫Now, this only works, remember, in production.
‫And so, if we did this now again,
‫then we would get the exact same thing.
‫And so, let's actually go back here
‫and run this in production.
‫So npm run start:production.
‫Yeah, just like that.
‫So if we try this now again,
‫let's see if we get our error.
‫And indeed, we do.
‫So if, right now, a user in production
‫tries to access our app with an invalid token,
‫well, then they get just this error message.
‫All right?
‫So that's the first error that we can get.
‫But another one is that the user
‫tries to access the application
‫with an already expired token.
‫And so, let's now try to create that error.
‫And in order to do that, I will change the time it takes
‫for the token to expire.
‫So right now, we have 90 days.
‫Let's put it to, like, five seconds.
‫Okay.
‫Give it a save.
‫And now try to log in again.
‫So let's actually save this one here, as well.
‫So, in users, and then log in.
‫So we can log in, and it will then give us a new token,
‫but this token is only valid for five seconds.
‫And so, these five seconds should have passed at this point.
‫So I will now copy this token
‫and try to access our protected route using that token.
‫So paste it here.
‫And now, let's see what we get.
‫And actually, for some reason, it did work.
‫So let's take a look at our JWT debugger again.
‫And it says, created May 2nd,
‫but expires only on July 31.
‫So something went wrong in that token creation, I guess.
‫And so, let's change this here again.
‫And I'm just gonna put five here.
‫And so, that five should then stand for five milliseconds,
‫or I can even, like, put 5000,
‫which should then be five seconds.
‫Okay.
‫So let me save it now again in order to restart the server.
‫Try it again.
‫So logging in again here.
‫All right.
‫So now all we need to do is to basically wait five seconds,
‫and that time should already have passed at this point.
‫Paste it here again.
‫And let's go.
‫And indeed, we get an error.
‫Now remember how this is basically the standard error
‫that we get in case we do not correctly handle that error
‫in our error handling.
‫Right?
‫So let's just take a look at the error.
‫And actually, we have it here in the console.
‫So let's see where that comes from.
‫And yeah, it comes from this place.
‫So this is the case in where we have an unknown error.
‫Remember, so an error that is not marked
‫as an operational error,
‫and so therefore we want to log it.
‫So we log it here
‫and then we send this generic error message
‫down to the client,
‫so the one we just saw in Postman.
‫But here we actually the details from this error.
‫And so, this one has the name of TokenExpiredError.
‫All right.
‫And so, let's now handle this one as well.
‫So I'm copying it now,
‫and then create just another if here.
‫So if the error.name equals this one,
‫well then, let's say,
‫handleJWTExpiredError
‫with the arrow.
‫Let's copy it and put it right here.
‫And so this, of course, is very similar to the one before.
‫Your token has expired.
‫Please log in again.
‫And again, with a 401 error code.
‫Okay, let's try that again.
‫And so, that's exactly the error message
‫that we should now see here.
‫All right.
‫And indeed, it is.
‫Great.
‫Let's finish the process here
‫and start it in dev mode, of course.
‫So npm start,
‫and all right.
‫So this one, we don't need any more, so let's close it.
‫Or actually, let's fix this small error here,
‫because indeed, we do not use this error here at all.
‫So let's get rid of it.
‫And then down here, we don't need to pass it in there.
‫Cool.
‫We, of course, also need to change this back to 90 days.
‫All right.
‫And so, just to be really sure,
‫let's log in here again,
‫copy the token,
‫and put it here.
‫Now, this process here of copying the token
‫and then pasting it here in this header
‫may seem a bit weird,
‫and actually we're going to fix that
‫in one of the future videos
‫so that basically, this process happens automatically.
‫But now, what's important is that
‫it's actually back to working now.
‫So we can actually get rid of this console.log here
‫and move on to the next step.
‫And we could actually stop here now if we wanted.
‫And again, most tutorials that you're gonna find out there
‫would, in fact, just stop here.
‫But this is not really secure enough just yet.
‫So for example, what if the user
‫has been deleted in the meantime?
‫So the token will still exist,
‫but if the user is no longer existent,
‫well then we actually don't want to log him in, right?
‫Or even worse, what if the user
‫has actually changed his password
‫after the token has been issued?
‫Well, that should also not work, right?
‫For example, imagine that someone stole the JSON web token
‫from a user.
‫But then, in order to protect against that,
‫the user changes his password.
‫And so, of course, that old token that was issued
‫before the password change should no longer be valid.
‫So it should not be accepted to access protected routes.
‫And so, that's the kind of stuff that we're gonna implement
‫here in step three and step four.
‫So the first thing to do
‫is to check if the user actually still exists.
‫And so, that one should be the easiest one.
‫So let's just say, User.findById.
‫And so, this is now why we actually have
‫the ID in the payload,
‫because we can now use that ID
‫and query the user using just that ID.
‫So decoded.id.
‫All right?
‫So that should then find the new user.
‫And of course, we need to await that
‫and then store it into a variable.
‫I'm calling it the freshUser.
‫All right?
‫Because it's not really a new user.
‫That's only when we create one.
‫But this is not really a new one,
‫it's really just the user based on the decoded ID.
‫Okay?
‫And we can do this so we can be 100% sure
‫that the ID is actually correct,
‫because if we made it until this point of the code here
‫then that means that the verification process
‫that we have previously, here, was successful.
‫Otherwise, this would have caused an error
‫which would then have prevented
‫the function from continuing.
‫And so, again, this verification process here
‫is in charge of verification
‫if no one altered the ID
‫that's in the payload of this token.
‫And so, because of that, we can be 100% sure
‫that the user for which we have issued the JWT
‫is exactly the one whose ID
‫is now inside of the decoded payload, so this one.
‫Okay?
‫So the verification process is really key.
‫It's really what makes all of this work.
‫Anyway, now what we need to do
‫is to check if there actually is a freshUser.
‫And if not, well then, of course,
‫we're going to return a new error.
‫So if there is no freshUser,
‫then return from this middleware
‫and call the next one with an error.
‫So this is a pattern that we've been seeing
‫over and over again at this point, right?
‫So the token
‫does no longer exist.
‫And actually, it's the other way around.
‫So actually, the user belonging to the token
‫no longer exists.
‫Right?
‫And then, the 401.
‫Okay.
‫So let's test this once again.
‫And let's actually create a new user for that.
‫So just test with the same password
‫so we're always using the same one here
‫just to make our testing a bit easier.
‫And I know that all of this testing here
‫makes the video take really quite a long time,
‫but of course, it's really important
‫that we do test everything that we do,
‫especially in such an important topic as authentication.
‫So I'm now using this JWT here, so I'm pasting it here,
‫but of course, before sending the request,
‫I will go ahead and delete that user right away.
‫Okay?
‫So again, let's pretend someone
‫created a user then logged in,
‫and let's say, then, after some time, the user was deleted.
‫But in the meantime,
‫someone could've gotten access to that JWT,
‫and could now try to log in as that user
‫that was, in fact, already deleted.
‫And so, again, we should not let that happen.
‫So let me delete this user here now.
‫And there we go.
‫And so, let's test it now.
‫And again, keep in mind that the user belonging to the ID
‫which is in this payload is now no longer there.
‫So let's see.
‫And indeed, we get this error message that we just created.
‫So that one is working as well.
‫And let's go to the last one.
‫So step number four,
‫check if user has recently changed their password.
‫So basically, after the token was issued.
‫And to implement this test,
‫we will actually create another instance method.
‫So basically, a method that is going to be available
‫on all the documents.
‫So documents are instances of a model.
‫All right?
‫And we do this because it's quite a lot of code
‫that we need for this verification.
‫And so, actually, this code belongs to the User model
‫and not really to the controller.
‫Okay?
‫And so, let's do that just like we did before
‫for checking the password.
‫So in User model, we already implemented
‫this correctPassword static instance method, remember?
‫And so, let's now create another one.
‫So userSchema.methods.changedPasswordAfter.
‫So function, and into this function,
‫we will pass the JWT timestamp.
‫So basically, that timestamp which says
‫when the token was issued.
‫So let's call that JWTTimestamp.
‫All right.
‫And by default, we will return false from this method.
‫And that will then mean
‫that the user has not changed his password
‫after the token was issued.
‫Okay?
‫So let's put that here, return false, basically by default.
‫Okay.
‫But then, we also have if this,
‫and remember that in an instance method,
‫the this keyword always points to the current document.
‫And so therefore, here we have access to the properties.
‫Now, we actually need to create a field now in our schema
‫for the date where the password has been changed.
‫So we don't have that yet.
‫So let's quickly add it here.
‫So passwordChangedAt,
‫and the type of it will be a Date.
‫Now, this passwordChangedAt property here
‫will always be changed, of course,
‫when someone change the password.
‫So right now, we don't have that logic anywhere,
‫and so nowhere we are actually defining this property.
‫And so, most of the documents, so most of the users,
‫they will simply not have this property in their data,
‫so in their object, right?
‫And so, of course, we need to test for that.
‫Okay?
‫So if the passwordChangedAt property exists,
‫only then we want to actually do the comparison.
‫Okay?
‫But if not, so if passwordChanged does not exist,
‫well then that means that the user
‫has never actually changed the password,
‫and so therefore we can simply return false.
‫So again, that's our default,
‫meaning that the user has not changed the password
‫after this timestamp.
‫Okay.
‫And now, just to start, let's actually log to the console
‫this.passwordChangedAt,
‫and of course, the JWTTimestamp as well,
‫just so we can see how we could compare them.
‫All right.
‫And now we need to actually create a user
‫which has this property on it, okay?
‫And again, later in the section
‫when we will implement the logic for changing the password
‫is when we will then set this property.
‫Okay?
‫But now we will artificially, basically, set it here
‫when we create a new user.
‫Okay?
‫So let's put that here.
‫And here, any date, actually, will serve.
‫So let's say 30 April 2019 here.
‫And so that should then be parsed into MongoDB just fine.
‫Let's try that, see if it works.
‫And that didn't work.
‫So it couldn't really parse the date, let's say.
‫And actually, I need to start with the year
‫and then the day at the end.
‫So 2019 and then 30 of April.
‫Try that again.
‫And so you see that now it's actually working.
‫So we have this parsed date here.
‫Okay?
‫Now, in order to actually see the result of this,
‫we, of course, need to call this method.
‫Okay?
‫So that's what we're gonna do here in step four.
‫Okay?
‫And so, remember that we can call this instance method
‫on a user document.
‫So freshUser.changedPasswordAfter,
‫and then that timestamp.
‫So that's at decoded.iat, so issued at, basically.
‫All right.
‫So let's simply see the result of doing that.
‫And so, of course, this should now, not here,
‫so this should now log to the console these two values.
‫Okay.
‫Now, of course I need to log in with exactly this user,
‫so with test,
‫so here we go.
‫Log in.
‫Copy this token here again.
‫And again, we're gonna basically automate that
‫in the next video, actually.
‫Okay.
‫Paste it here.
‫And now, we actually get this bug here.
‫So I just misspelled this function name here.
‫Well, let's just copy it.
‫Try it again.
‫Oh man.
‫What's going wrong now?
‫And I see I simply forgot this log here.
‫So another stupid mistake.
‫Probably saw that one coming.
‫But now here we go.
‫So everything worked fine,
‫and all we really wanted to see for now
‫is these two results.
‫So we basically have this one here this date format,
‫and then the other one
‫in this millisecond or second timestamp here.
‫And so, we now need to convert this passwordChangedAt
‫also to a timestamp like that.
‫All right?
‫And so, for that, let's create a new variable.
‫So changedTimestamp.
‫And we can use this.passwordChangedAt.getTime.
‫Okay?
‫And so, that's one of the many, many date functions
‫that JavaScript gives us.
‫All right.
‫And now, let's quickly compare these two
‫because we're not quite ready yet, actually.
‫So sending it just to see the results here.
‫And so what we see here basically
‫is that this one here is now, basically, in seconds,
‫and this one in milliseconds.
‫So it's 1000 times more.
‫And so, we know we need to divide this by 1000
‫and then parse this entire thing as an integer.
‫And for that, we use parseInt.
‫So another JavaScript function that's available for numbers.
‫And then we actually also need to specify the base.
‫So this is a base 10 number.
‫All right?
‫And so now, let's actually, again, see the result.
‫And now, that looks a lot friendlier.
‫Okay.
‫And so, now let's actually return our result.
‫And again, keep in mind that false means not changed.
‫Okay?
‫And not changed basically means that the day or the time
‫at which the token was issued
‫is less than the changed timestamp.
‫Okay?
‫So just as an example here,
‫let's say that the token was issued at time 100.
‫But then, we changed the password, let's say, at time 200.
‫Okay?
‫And so, we changed
‫the password after the token was issued,
‫and so therefore, this is now true.
‫All right?
‫And that's exactly what we want to return here,
‫because false means not changed,
‫and so true, of course, means changed.
‫And so, that's exactly what we have here.
‫But now, let's say that the password
‫was last changed at 200,
‫but then only after that, we issued the token,
‫so let's say, at time 300.
‫And so, 300, less than 200?
‫No, that's false.
‫And so, we return false, which again means not changed.
‫And so, that's why we use this less sign here.
‫Okay?
‫Let's go back to our controller and actually use this.
‫So if the password was actually changed,
‫well, in this case, we actually want an error.
‫So return next, again, a new AppError.
‫Recently...
‫Please log in again.
‫Okay.
‫And once more, code 401.
‫All right.
‫So again, this will return true
‫if the user actually changed their password.
‫And so, if all of this here is true,
‫well, then exactly in that case
‫is when we want this error to happen.
‫All right?
‫So that was actually the last step.
‫Okay.
‫So basically, if the code can make it all to the end
‫of this code here, only then, next will be executed.
‫And then, with next, we go to the next route handler,
‫which effectively means to grant access
‫to that protected route.
‫Let's actually put that here.
‫Grant access to protected route.
‫Okay?
‫Because that's really all this next does.
‫Next leads us to the next middleware,
‫which is usually, then, the route handler itself,
‫so the one which sends back the data that was protected.
‫Okay.
‫Just one last thing that we want to do here
‫is to actually then put the entire user data on the request.
‫So we can simply say, req, so request, .user
‫will be equal to the freshUser.
‫Okay.
‫And again, of course,
‫the code only ever reaches this point here
‫in case everything is correct.
‫Okay?
‫And so, this here might then be useful
‫at some point in the future.
‫Great.
‫Let's just test this one more time.
‫And basically, this change is in the past now.
‫And so, this token that we have here,
‫or actually, I could have reused just this one
‫instead of logging it again.
‫But anyway, this token was issued
‫after the password changed.
‫And so, this token should now work.
‫So let's actually log in again
‫and try it with this token.
‫And indeed, we get access.
‫Now, moving to Compass in order to change that date.
‫Okay.
‫Let's put it one month later.
‫And so, that will actually be in the future,
‫so at least, in my future when I'm recording this video.
‫Of course, you will be doing this at a later point.
‫And so, to test this, please put this in your future.
‫So in the future of the date
‫where you're watching this video.
‫So if I go now back to Postman and log in again,
‫okay, so if I log in again now
‫and try to access that route,
‫well, then this token will be issued, basically,
‫after the password has been changed.
‫Or actually before the password has been changed.
‫So, sorry for that confusion.
‫So the password was changed at May 30,
‫but this token was issued at May the 2nd, and so, before.
‫So basically, it's now as if the user
‫had changed their password after the token was issued.
‫And so, that's exactly the situation
‫where we don't want to give access to the protected route.
‫And so, this should now then reflect that.
‫And indeed, user recently changed password,
‫please log in again.
‫Great.
‫So that now works.
‫So our protect middleware is now completely implemented.
‫Let's just get rid of this console.log here.
‫Don't need that one any more.
‫And okay.
‫So let's quickly recap,
‫and this video is running very long,
‫bit longer than I expected.
‫But it's really important to understand
‫and to explain how all of this works
‫and why it's important.
‫And so, I prefer that than doing this video's much shorter.
‫Of course, I could just write the code,
‫but then you wouldn't really understand what's going on.
‫So this part we already understood.
‫Then this part, I believe as well,
‫so this is where the verification happens,
‫so basically seeing if the token payload
‫has not been manipulated by some malicious third party.
‫Okay?
‫And since we then reach this code here,
‫it means that no one changed the JSON web token,
‫and so therefore, we can get a fresh user.
‫So basically, we can get the current user,
‫let's actually call it currentUser.
‫Why not?
‫So here, here, and also here.
‫Okay?
‫So we can get the currentUser from that ID
‫that was just decoded from the payload.
‫Now, if the currentUser does not exist,
‫so this is what we're testing for here,
‫well, then in that case
‫we do not want to give access to the route,
‫and instead create this new error.
‫But if the user does exist,
‫well, then we make it to point number four,
‫where we then check if a password change has happened
‫after the token was issued, right?
‫And if it did, then again, we create a new error.
‫And if it did not, well,
‫then we make it to all the way
‫to the end of the middleware function,
‫where we then assign the currentUser to request.user
‫so that we can then use it in a next middleware function.
‫Okay?
‫Because remember, this request object,
‫this is the one that travels, basically,
‫from middleware to middleware.
‫And so, if we want to pass data
‫from one middleware to the next one,
‫then we can simply put some stuff on the request object,
‫and then that data will be available at a later point.
‫All right.
‫So, that's it.
‫This is a very sophisticated
‫and very complete route-protecting algorithm, basically,
‫but I think it's really important
‫to do it as well as we can.
‫Anyway, glad to see that you made it
‫to the end of this big video,
‫and I'll see you in the next one.