Check out a free preview of the full API Design in Node.js (using Express & Mongo) course:
The "Authentication with Middleware" Lesson is part of the full, API Design in Node.js (using Express & Mongo) course featured in this preview video. Here's what you'd learn in this lesson:

Mongoose allows new methods to be added to the Models and Documents in the application. Scott explains how these new methods will allow a middleware API to be built around the authentication process by using lifecycle events like “before save” and “before validation”.

Get Unlimited Access Now

Transcript from the "Authentication with Middleware" Lesson

[00:00:00]
>> [MUSIC]

[00:00:04]
>> Speaker 1: So, there are so many ways to do this password process with Express and Mongo. So many ways, I don't think there is a right way. You can make a middle ware globally, you can put one on the route. You can put one on the router, you can jut have a utility function that you require and use everywhere.

[00:00:20] There's so many ways you can do this one thing. But Mongoose allows us to teach our models and our documents new tricks by adding custom functions to them. And this is where we're gonna do it. Because it makes sense to do it, to me at least, on the actual models.

[00:00:34] Because those are the things that are gonna save the password. So instead of having express or node know about hashing passwords. I should just tell all my models about it, like, hey, you know how to hash a password, hash yourself, or check yourself versus, node, check this password on this model.

[00:00:49] All right, so just check yourself and tell me if you're right. So, to teach Mongoose about new tricks there's a couple ways we can do it. So, when we have our schema object that we create we can use the .methods property and that's going to be an object, and we can just make functions on it.

[00:01:12] This is like the equivalent of like calling function.prototype.whatever. It's like adding stuff to the prototype of the dog. That's what methods is, it's adding to the prototype cuz these functions that we're making, these instances or these methods, are gonna be only available to the instances, not the dog itself but only the instance of a dog.

[00:01:32] So, just like .push on an array is not available to the array constructor but it is available to array instances. So I can't say array.push.
>> Speaker 1: Or, let me try to call it. That's not a function, because push is not part of the constructor, it's part of the instance.

[00:02:02] So I can say give me an instance of an array and call push, and that will work.
>> Speaker 1: So it's the same thing.
>> Speaker 1: That's what the methods object does, the inverse is the statics object. And statics is like adding it to the static property
>> Speaker 1: So, again, for inside of methods and we come to the log this, it will be the current document.

[00:02:29] If we're inside of a static method this is gonna be actually the constructor, the dog. So that's the equivalent of doing this. So I just gave an example of like, you can't do array.push cuz that's an instance method, or prototype method. But, what we could do, array has its own methods, like Array.isArray.

[00:02:51] That belongs to the array constructor, but it doesn't belong to the instance. So, if I said Array.isArray. That doesn't work. Because it doesn't belong to the instance of a raise. It only belongs to the constructor itself. It's the same thing. So statics belong to the dog model. Methods belong to the dog instances.

[00:03:16] So, if we wanted a dog to bark, like, hey dog, bark. We'd put it on the instance, like we'd put it on the methods, like, can you just go bark? If we wanted all dogs to be able to do something, like, I want all dogs to be able to, or I want to be able to find all dogs by their owner.

[00:03:32] Here, I have that here. So, I can make a new method on here. So I can say dog.findbyowner. I give it the owner's name and it'll find it. So I could do that. Any questions on that?
>> Speaker 1: Again, this is with Mongoose, not Mongo. Mongoose is allowing us to do this.

[00:03:56]
>> Speaker 1: So Mongoose, like Express, also has support for middleware. And middleware is perfect for validating, changing, notifying, etc. It's the same use cases that you would use in middleware in Express. But just now we have middleware on our models. And these middleware, they tie into the life cycle events around our documents.

[00:04:18] So when I say life cycle events, I mean things like I wanna be notified before something saves or after something saves or before something is validated or after something's created or after something was removed. We can create middle wear to attach those life cycle events and will notify us about it.

[00:04:36] Okay. Hey something's about to save here. You can do something right quick if you want to Or something just got removed. You wanna do something that's what allows us to do. So we'll use middle way to hash our passwords before users created these in appropriate place to do it.

[00:04:50] You can, like I said you can this in so may places. You just have a function that you just call throughout your, I mean you can do it inside the controller, I don't think it'd be the best place to do it but you could. But we're just going to do it inside of our middleware.

[00:05:02] So the way middleware looks in mongoose, so again on the schema you either do a .post or .pre. Post means after this event, and pre means before this event. You can go look at the docs they have tons of Hooks you can hook into. So here's an example of me wanting to run a call back after a dog has been saved.

[00:05:26] So, dog.post, that means after dog has been saved. Run this function. So, anytime a dog has been save, and I think save only runs on create. It doesn't run on update. So if you updated something I don't think that counts as a save. So, what I can do is, okay, assume that this socket is a web socket library.

[00:05:47] I can just send an event to the client who's like, hey, I'm notifying you about a change so that way you're getting real time updates whenever dog is being changed. Whenever somebody else in the world adds a new dog to our database All the clients get updated about it.

[00:06:00] So, this is where you'd do something about it. And then, of course, just like Express, you'd have to call next to go onto the next middleware. And just like Express, you pass in the error object here, it will pass in the error and log it out.
>> [NOISE].

[00:06:18]
>> Speaker 1: Here's an example of how we can tie into a callback function before our model is validated. All right. So we, we set up all those validations on our models, like required, unique. Min length, max length, this will happen before Mongoose ties into those validations. So maybe you have a validation of, like we were talking about yesterday, you were saying, RegExes.

[00:06:40] So you can do those RegExes right here. It's like, all right, this is where I'm gonna test. I wanna make sure that it files this, or I wanna make sure that It's all lower case or something like that. So you would do stuff like this. And you get access to the document just by calling this.

[00:06:55] So when you say this, they'll get the doggy. So then you like all right, doggy.name.test, this regex, or.match this regex. And then of course you've got to call next. If you don't call next it'll hang
>> Speaker 1: Any questions on that? It's like the same thing as Express middleware.

[00:07:15] It just ties into hooks.
>> Speaker 1: So, when you call next, it just goes to the next hook. Not the next middleware that you made. It just goes to the next hook. So, for instance, pre-validate runs before presave, so prevalidate you'll do your stuff, call next, then it'll go to presave, you can do some stuff, then it'll call X, then it might go to post save, you'll do some stuff, so all three of those are one time a document will save.

[00:07:50]
>> Speaker 1: Cool, any questions on this? Yeah?
>> Speaker 2: So, this is all still running in our Express environment, right?
>> Speaker 1: Yes.
>> Speaker 2: It's not like this is running in some separate thing, or.
>> Speaker 1: Nope.
>> Speaker 2: Okay.
>> Speaker 1: Yeah, you should see it, like right now.
>> Speaker 2: So, that omit, we could tie some other code to that, and when that gets omitted, we.

[00:08:11] We subscribe, right?
>> Speaker 1: Yep. It's all in. Great, so now that we know that, we need to do a couple things. So first, let's check out to step ten? Yeah. Yeah, question.
>> Speaker 2: Do we need to do input senatization for mongoose? And would you do it in the .pre?

[00:08:35]
>> Speaker 1: The way to do what?
>> Speaker 2: Input sanitization.
>> Speaker 1: Yeah. So, again, that's something I would totally do on a as well. So would totally sanitize stuff on the front and the first but then as a back up, yes, you would totally do it And something like, what are these middlewares exactly?

[00:08:54] Anytime you need to check or alter or verify something on a model before it gets processed on a database, this is the perfect place to do it. But again, you also could do it in a mongoose, like express. There is nothing stopping you from doing it there. It just.

[00:09:11] I just think this is not the appropriate place to do it.
>> Speaker 2: And then, this was a little while back but is there a recommended NPM module for handling auth rules and Passport js? Was brought up.
>> Speaker 1: Yeah, passport js is definitely the go to. That's like the think.

[00:09:27] We're not gonna use password today, I use password all the time, but we're not gonna use it today because I want you just make it yourself cause it's not that hard to do it yourself. But yeah, if I were going to use authorization rules in note, I would totally use passport js.