API Design in Node.js, v3 API Design in Node.js, v3

Protect Routes with JWT Solution

Check out a free preview of the full API Design in Node.js, v3 course:
The "Protect Routes with JWT Solution" Lesson is part of the full, API Design in Node.js, v3 course featured in this preview video. Here's what you'd learn in this lesson:

Scott live codes the solution to the tests where it looks for the Bearer token in the headers, the token must have the correct prefix, it must be a real user, and finds the user form token and passes it on.

Get Unlimited Access Now

Transcript from the "Protect Routes with JWT Solution" Lesson

[00:00:00]
>> Scott Moss: So for protect, let's see what the tests say. Looks like we have to look for a bearer token in the headers. Must be correct prefix as in bearer, must be real user and finds user from token and passes it on, so those few things. So to do that, first thing is let's grab the token.

[00:00:18] So grab the token, so I'm just going to do let because I reassigned this a couple of times. It's going to be req dot headers dot authorization. So I'm gonna get the token there, and then I'm going to split on Bare with a space. If I can spell it there, so I'm gonna do that, and then if not token.

[00:00:51] So if there's well now token's gonna be like an array, and I wanna get the first thing. Because if this works out, then I should get back an array that looks like an empty space, and then my token, over here. If they formatted correctly, it should be something like that.

[00:01:10] So I wanna get the first thing in it. So if there is no token, then I wanna go ahead and say, res.status(401) .send(message: 'no auth'). So that'll take care of it's no token and then the next thing I wanna do is I wanna verify if this is a token or not.

[00:01:38] So what I can do is const payload =, I'll use a verified token method that we have above which takes a token and it verifies it.
>> Scott Moss: This one right here, and it's asynchronous.
>> Scott Moss: So we'll await that.
>> Student: Return in front of that res.status.
>> Scott Moss: Yes, thank you.

[00:02:03] That would've caused major problems. So we got the payload, so that'll check to see, if this works, this will give us back the user. If it doesn't work, it's gonna break, so we'll do a try catch here.
>> Scott Moss: And we'll just log the error just in case.
>> Scott Moss: And I will just send back message if it doesn't.

[00:02:33]
>> Scott Moss: Cool, so if it is, then the next thing we wanna do is, you must be the real user, so we need to query for the user in this case, so let's say user = await User dot find by id. And it'll be on payload dot id. The reason I know it's on payload id is if I go look above on the way it's signed, I signed it with a payload of an id who is user id, so when I get it back from verify token it'll be the same thing it was when I signed it.

[00:03:02] And there's a .ID property on it, so that's what I'm using as a user ID. User goes in on sign, user comes out on verify as the same object. So, I have an Id project there, so that's how I know that there was an Id on this payload, cuz it's that same thing.

[00:03:18] So I'll go ahead and accept that. And because I don't wanna add the passwords on there, I'll go ahead and select and remove the password from beyond there I don't want that. And then it says must pass it on, so what I'll do is I'll say req.user equals the user and then I'll say next to continue cuz this will be middle ware.

[00:03:48]
>> Scott Moss: So let's see if this works.
>> Scott Moss: We'd go up here.
>> Scott Moss: It looks for Bare, okay. Looks like not of the tests passed on that one. So let's see how much they've got the formatting off, for like the status codes and stuff. So this is, specs a 401, and a .and, and a .and, and a .and, yeah, so, all these are .and.

[00:04:30]
>> Scott Moss: There we go, and we'll see what happens, do that.
>> Scott Moss: Cool, so we got a solid pass here. So a token must have the correct prefix, got that. Must be a real user. Looks for a Bearer token in the headers that didn't pass. Finds user from token, passes it on.

[00:04:52] So that didn't pass it, so what we'll do is find user from token passes it on. This is expecting correct.user to ID. Okay.
>> Scott Moss: Okay, so we'll get to that one. And the first one that failed was looks for Bearer tokens in headers. It's cuz if you don't pass a header, it should fail.

[00:05:12] So we should do that. If not req.headers.authorization, then do this, so that was it for that. Run the test.
>> Scott Moss: Okay, and it looks like we got the last one, which is, finds user from token and passes on. So that one is looking for the token here, authorization, next.

[00:05:46] Okay, expect(rec.user, _id.toString. Okay, so let's check that out.
>> Student: [INAUDIBLE]
>> Scott Moss: No, it should just be payload, let's check it out.
>> Scott Moss: Should we, payload should be fine.
>> Scott Moss: It's not id, because I put this id here like that, yeah, so that should be fine.
>> Scott Moss: Looks like not to have property.

[00:06:30] It looks like I am getting it back. I'm just got a little mismatch with something that's off here. I think I know why, it's because I need to call it .lean in here I believe. Dot lean just converted to JSON, because right now it's a Mongoose document. I think it just wants it to be a JSON document.

[00:06:58] See if that was it, yeah, that was it. The only other way you can do that is if you do user dot two JSON like that, it's the same thing, but these are documents I could return from the database, and it's just expecting it to be a raw JavaScript document and not a Mongoose document, so that's what that was.

[00:07:19]
>> Scott Moss: And so that passed those tests, and then now we need to add these to the route. So we'll go to server and we'll add them here, so we'll say app. Post('/signup', signup) and we'll do the same thing for sign in, and we'll add signin here, cool. And then, to lock down the routes, and that should've imported them, it did.

[00:07:48] To lock down the routes we'll use the protect middleware here. And again, we can add them like this, protect, and add them again here, protect. But that's just tedious. So what I'm gonna do instead is I'm just gonna say app.use, anything with /api just protect. And as long as I add that before these, it'll run this middleware and then if it succeeds it'll call next and it'll go to where it's supposed to go.

[00:08:16] I would prefer to add the protect middleware to here at the mount path of /api because this is a lot less tedious to write, and if we run our test, that should satisfy.
>> Scott Moss: Yeah, so all of our tests pass now.