API Design in Node.js, v5

Security Best Practices

Scott Moss
Netflix
API Design in Node.js, v5

Lesson Description

The "Security Best Practices" Lesson is part of the full, API Design in Node.js, v5 course featured in this preview video. Here's what you'd learn in this lesson:

Scott discusses applying authentication middleware at the router level for consistent security, centralizing logic, and maintaining endpoints. He also covers best practices like avoiding logging tokens, using HTTPS, token expiration, refresh tokens, and request validation.

Preview
Close

Transcript from the "Security Best Practices" Lesson

[00:00:00]
>> Speaker 1: And then yeah, let's do the same thing for the User Routes, so we'll go in here for our router Router.use, authenticateToken Easy Same thing, yes So that protects everything underneath it, right Yeah, it does You could use middleware for that too Or would you Well, technically this is middleware We're just putting it globally for this router subset

[00:00:00]
Are you asking if I can put it here Yeah, I could I would do the same thing It depends on how granular you want to get, right So I'm saying I'm okay with every one of these things being locked down, so I'm just gonna do it up here But if you're saying well, all but one should be locked down, so I would put it on each one instead, except for the one that I don't think needs to be locked out

[00:00:00]
And that's fine too However you want to do it, but I think each one of these routes should not be accessed by someone who's not authenticated, so I'm gonna lock this whole tree down Middleware can be handled at different levels Let me go back to my notes Here we go, understanding router level versus route level, right

[00:00:00]
So our approach is a router level where we pick a router, whether it's the global router or a sub-router or even a grandchild router, we do it there This will protect all the routes in the router, it's clean, it's consistent You can't forget to protect their route It's one single point of control There's nothing wrong with doing it route by route either

[00:00:00]
It's just more verbose Sometimes you forget where it might be because it's in so many places, and it's useful for mixed auth routes I would say this is probably a solution for a subpar routing naming Like if you didn't do a good job of creating good routes and segmenting them, and there was like a mix of some that have to be protected and some not, then this would be the solution for that

[00:00:00]
It's putting them as local as you can, but if you did a really good job of segmenting your routes out to begin with, you could do them higher up in one place because you group the routes based on "yeah, all these routes have to be locked down." Whereas if you just made routes willy-nilly, everything is everywhere, you're gonna have to get very granular

[00:00:00]
You could technically do it another way because you could do whatever you want in middleware There's nothing stopping you from adding that authentication middleware globally, like "I'm gonna lock the whole app down," right So by default, this will lock the whole app down, which we don't want for auth But what you could do in this authenticateToken is very similar to what you would do in middleware for Express.js

[00:00:00]
You could just look at the request object and see what URL this request is trying to go to And then you could be like, "Oh, if it has '/auth' in it, it's good, don't worry about it," and that way you can still put it at the top in one place Programmatically within the middleware, you'd be like, "Ignore anything that has '/auth', don't worry about protecting that." Or "this one special route right here is good, ignore that too." So you basically make an allow list of routes that are fine

[00:00:00]
But that could introduce other problems too because now you have more than one place where a route is defined The route is defined itself on a router level, and then you have a reference to that same router inside some allowed list If you ever change the name of that route, now you've got to change it in two places You can get around that by making constants, and I made all my routes in constant variables that I can export everywhere

[00:00:00]
So if I ever change the name of a route, I only have to change it in this one file There's an answer for everything, but it depends on how complicated you want to get Some security best practices: Never log tokens They're sensitive The only time I've ever had to log a token is when I thought someone stole a token Obviously use HTTPS in production

[00:00:00]
Tokens sent in plain text over HTTP can be intercepted Please set a reasonable expiration date, especially if you use refresh tokens Just refresh the tokens when needed Validate on every single request Don't cache authentication state Just because you were authenticated today doesn't mean you're still authenticated tomorrow

[00:00:00]
Your server should have amnesia – treat each request like it's the first time Some other pitfalls: Don't forget to put the "Bearer" prefix on tokens Be aware of case sensitivity with the Authorization header Different servers handle this differently Also, make sure to handle async errors in middleware, or your server could crash

[00:00:00]
Now that the handlers or controllers follow the authentication middleware, they have access to req.user This means we can now safely write methods for getting habits or entries for this specific user, because we know who the user is.

Learn Straight from the Experts Who Shape the Modern Web

  • In-depth Courses
  • Industry Leading Experts
  • Learning Paths
  • Live Interactive Workshops
Get Unlimited Access Now