API Design in Node.js, v3 Secure An API with JWTs Exercise
This course has been updated! We now recommend you take the API Design in Node.js, v4 course.
Transcript from the "Secure An API with JWTs Exercise" Lesson
>> Scott Moss: So for this exercise what you're gonna be doing is you're gonna be locking down our APIs using JWTs. So checkout to the lesson-5 branch. The first thing to do is you're create a sign-up controller. So what is that? In that same file you'll see these three functions down here, signup, signin and protect.
[00:00:18] So in order to authenticate and have people use our API. We need them to sign up and sign in. And this is where I said some routes just don't work well with rest. Authentication just really doesn't work well with rest. You just can't really do authentication rest it kind of just needs their own route.
[00:00:32] So that's where sign up and sign in are here, and they weren't there before. So it needs a lot of people to sign up and these are controllers, right, request and response. So you will need to implement the sign up logic for our API, which means you have to accept email and password which is basically just creating a user.
[00:00:53] But the most important part is you have to send back an adjacent web token. You don't have to worry about hashing the password or doing anything like that cuz that's already done for you in the database. If you go look at user.model, I'm already doing that for you here.
[00:01:06] So every time a user's created I hashed a password. I even allow you to check the passwords, so you'll need that on signin. So you don't have to worry about that part, that part's done. The part you're specifically worried about is gonna be with JSON web tokens. So we have to create signup, which creates a new user.
[00:01:21] And it's successful. It responds back with a token that you have to use the new token method to create. So that's one thing. The next thing you have to do is you have to create the sign in controller which is very much like the sign up, except for creating a new user, it checks to see if the credentials that are coming in, the email and the password, are valid.
[00:01:41] In the database. And if that is true, send back a new token the same way the signup would. So to send back a new token if the signin is successful. And how do you know if the signin is successful? Well, if the email and the password matches. And again, the passwords are hashed, so in order to check the passwords you'll have to use User.checkPassword.
[00:02:06] So on the user model, you will have access to a checkPassword function that takes a password. And from there, you'll be able to check the password, I'm sorry, not on the user model, on the user document, the instance of the user. When you crawl the database and you get a user back, that user itself will have a check password function on it that you can pass in a password that you wanna check and it'll compare the two to see if the hashes match up.
[00:02:33] So you don't have to worry about doing that but you will have to do that and sign in. So given a password against the user, check to see the passwords match. If they do, Create a token. If they don't, they're not authorized.
>> Scott Moss: The last thing is, you've got to create a protect middleware to lock down the API routes.
[00:02:54] So, cool, we've got, we have sign up and sign in. But now we've got to protect our API routes. So, this is going to be middleware. So, what you're going to do here, this is where you're going to verify the token. So, in every single route, every single request is slash API.
[00:03:07] You need to run this middleware protect. It needs to execute. And its job is to look for the adjacent web token in the authorization header. So, if you look in the authorization header, you'll see a token on there. You need to grab that token and you need to run it through verify and if verify passes, it's good.
[00:03:27] If it doesn't pass, it's a wrong token or somebody's trying to attack your website. Yes?
>> Speaker 2: And we're protecting all routes the same way? We're not differentiating between routes?
>> Scott Moss: Every route that's mounted at slash API should use this. Yep, so you wouldn't put this in front of sign up and sign in.
[00:03:44] Because then you couldn't sign up or sign in. But you will put this in front of all the other ones. But if you go look at server JS, this is where you're gonna add those routes. So after you make sign up and sign in, you need to register them here.
[00:03:56] So you do like a app. Post signup app. post signin and you'll put those controllers there. And then for API you would add your middleware either here, here, and here. Or you can make a new mount for everything at API use this one. And it'll work for everything below it.
[00:04:13] So it's up to you how you want to add that. But you will also have to add those routes here.
>> Scott Moss: So I'll give you a tip. The thing you're gonna run into that's gonna be the most difficult at first for sure is gonna be protect. These signup and signin are not that difficult but protect might be.
[00:04:30] But because the format of the way that JSON web token comes in. A JSON web token comes in a format like this. So if you look at the authorization header you'll see something like "Bearer " and then a space, and then you'll see the token here. It's gonna come like that.
[00:04:45] That's how it's expected. If you don't see it like that, then it's not correct. And the test is testing for that. So if it comes in just as a token, then that's not right. If it comes in as a token would something or bearer with something after. That's not right.
[00:05:03] It has to come in just like that. And that's what the test is testing for. And you can look at the test and see what exactly I'm talking about. But that's what this function should be testing for is that the token looks like that, and then you pop the token off and you pass it to verify token to see if it's real or not.
[00:05:18] So one, does it have a token? Two, is it formatted correctly? Three, is it a valid token? If all three of those pass then you're good to go. I think protect is also its job is to take it a step further. And not only verify the token, but then go look in the database and get the entire user.
[00:05:37] And attach it to their request object before calling next. So after you verify the token, you then need to do a database query to see if this user exists. So cool story you gave me a valid JWT, that hasn't been expired yet, but that user just deleted their profile yesterday.
[00:05:52] So I need to see if they're a real a user in our database. So that's why you take that extra step to see even if they pass the validation, is this even a real user still? So that's why you do that extra database crawl. And again, the test is testing for that as well.
[00:06:05] Any questions on that? Yes.
>> Speaker 2: The name of the test is testauth?
>> Scott Moss: Yes, so to run the test, you're just going to run test npm run test-auth.
>> Scott Moss: There you go. And you'll see a whole bunch of test failing here.
>> Scott Moss: So there's already a test for new token or verified token, but those are already done for you.
[00:06:37] But then here's a test that you'll have. You've got two tests for sign up. You got four tests for sign in and about four tests for protect. And they're pretty detailed so I'll be helping out if you get stuck, just let me know. But it's four o'clock now.
[00:06:52] We'll come back at 4:20 and go over the solution.