API Design in Node.js (using Express & Mongo) Usernames & Passwords
This course has been updated! We now recommend you take the API Design in Node.js, v4 course.
Transcript from the "Usernames & Passwords" Lesson
>> Speaker 1: So the process is like this. A user signs up to access protected resources on our API. So that means they give us a username and a password. They sign up. On success, we create a new user in our database, right? So it's like cool, that user name is great, it's not taken.
[00:00:23] The password matches our validations, whether that's like a min length, or a max length, or whatever the validation was, if any. Great, we create a new user name in our database, you're good. So typically what you would do there is you'd like, all right, now in a sophisticated system you'd probably say, and I'm going to make a new session and sign them and sign a cookie, send that back to the browser.
[00:00:43] But, now what we're gonna do is we're gonna grab that new user's ID that we just saved in a database and we're gonna create a JSON web token, just like we did up top. We didn't send that JSON web token back to the user on the response of sign up.
[00:00:58] So, when they sign up, they should expect to get back a token string. It's like, here's your token. You signed up successfully, here you go. And then what the client's responsibility is is to save it somewhere that will persist so they can use it for every request. So they have to save it somewhere.
[00:01:16] And every time they make a request to the server, for like some protected resource, they have to attach that token to the authorization header or the query string or wherever our server says it needs to attach it. In this case it's the authorization header. It's up to you when you build out your backend, but I think the spec is, put it on the authorization pattern.
[00:01:40] And they have to do that on every single request when they want something. Just like a cookie is sent on every single request from the browser by default. You just have to send this too. And most sophisticated client frameworks allow you to automatically do things like that so you don't have to do it every time as well.
[00:01:55] I know Angular does, it's like, you write interceptors, like every time I make a request to the endpoint, attach this to the header. It'll do it for you.
>> Speaker 1: So not only did we get authentication with that we also get identification, right? Because the jwt has ID, so you get two things out of that.
[00:02:16] And if we had a roll based auth flow, we could also get authorization from that as well. Maybe not only would we attach IDs on here, but we would attach the users rolls on this object too, that way we can get authorization on what they can and can not do on different access levels.
>> Speaker 1: So with JWT as a method. We will use to grant access to our protected resources. We still need a way to, excuse me, sorry. My eye is really bothering me.
>> Speaker 1: We still need a way to actually create users other than a simple POST request to the server.
[00:02:56] So, right now the way that we create servers, if you go look at our endpoints, just do a POST request to the user's resource with their username and you create a user. It's not that safe, right? That's not what we really wanna do. So we need a better way of doing that.
[00:03:11] So the way we'll do that is with a user name and password.
>> Speaker 1: So we all ready have a user name field that is unique. Let's add a required password field as well to help identify who a user may be when they sign in. So there are numerous problems around storing original plain text passwords in our database, if you haven't experienced databases.
[00:03:32] There are legal, technical, and moral problems around storing people's passwords in your database in plain site. You're just asking for it if you do it. Just saying. If you store somebody's password as is in plain text on the database, you're asking for it. So instead, we will store a hashed version of a user's password.
[00:03:54] Note that sending plain text passwords over HTTP is not safe either, and you should be using HTTPS instead. We will not be using HTTPS. So, just get over that for now. If you're again, a security person, I don't wanna send this password over HTTP, it's okay. My wife's gonna hack us today.
>> Speaker 2: I'm intercepting.
>> Speaker 1: [LAUGH]
>> Speaker 2: Couple questions. If you use JWT, do you have to make sure you're in a browser that supports client side storage?
>> Speaker 1: Yeah, you'd probably, I mean if you wanted to persist yeah. I mean you could theoretically just save it in cache. Right and then if you refreshed the browser then you'd just have to sign in again but yeah if you wanted to persist if you want a good user experience where the user doesn't have to sign in every single time they come back, then yeah, you need storage.
[00:04:41] But if you don't have storage, then the worst case scenario is that every time your app loads up or loses state, the user has to sign back in. So that's worst case scenario. But yep, you definitely need that, so. And most browsers do, I mean definitely the major browsers support that down to like older versions.
[00:04:59] And of course mobile devices support that as well.
>> Speaker 2: And then they're asking you're gonna hash and salt passwords?
>> Speaker 1: So, we're gonna talk about salting, but yeah, we are.
>> Speaker 1: So, unlike the encryption of a JWT we can't undo the hash of a password. We can't say, okay here is the hash give me back the password, like we can with a JWT.
[00:05:29] With a JWT, we're using encryption and we're using this shaw and this is like if I give you back the token with the same secret I expect the object that I encrypted before. Whereas a hash doesn't really work that way, it's a one way thing. It's like I'm just gonna create a hash and that's it.
[00:05:48] And the only way to check if something equals a hash is to hash it again and see if the hash values match, not the actual passwords. So we can't undo the password. This is why hashing is perfect for passwords. So in order to check to see if the given password matches a safe hash password like on sign in which is exactly what sign in is.
[00:06:10] Sign in is like, first let me see if there's a username in our database with this, great there's a username. Now let me grab that user's hash password in my database, let me grab the password he just sent me. Let me hash this password and compare it to the safe hash password.
[00:06:25] If it matches then they are who they say they are. Let me sign them in. That is what sign in is. So again, using the same hashing function in the password, we will get the same hash as we did on sign up. There are further methods we could use to prevent attacks on our API and our database like creating unique salts for each user and storing the salt on the user to help prevent rainbow text.
[00:06:50] So, we're not gonna be creating unique salt so we'll just generate the same salt for now. But yeah, you could and in fact you probably should, creating unique salts and storing them with the user themselves. So a hacker would just have to work a little harder to getsalt.
[00:07:04] But ultimately you can't stop anybody from doing anything, it's just gonna happen. You can just make it harder.