Would you like to inspect the original subtitles? These are the user uploaded subtitles that are being translated:
1
00:00:01,260 --> 00:00:02,480
So in this lecture
2
00:00:02,480 --> 00:00:04,560
we're gonna implement the functionality
3
00:00:04,560 --> 00:00:08,010
of logging users in based on a given password
4
00:00:08,010 --> 00:00:09,363
and email address.
5
00:00:10,920 --> 00:00:14,520
And just like before, the concept of logging a user in
6
00:00:14,520 --> 00:00:17,400
basically means to sign a JSON web token
7
00:00:17,400 --> 00:00:19,760
and send it back to the client.
8
00:00:19,760 --> 00:00:22,390
But in this case we only issue the token
9
00:00:22,390 --> 00:00:24,860
in case that the user actually exists,
10
00:00:24,860 --> 00:00:27,310
and that the password is correct.
11
00:00:27,310 --> 00:00:29,773
So, let's start to implement that.
12
00:00:31,480 --> 00:00:36,260
Exports.login is...
13
00:00:39,090 --> 00:00:42,253
request, responds, and next.
14
00:00:44,370 --> 00:00:47,060
And the first thing is we is to actually read the email
15
00:00:47,060 --> 00:00:50,020
and the password from the body.
16
00:00:50,020 --> 00:00:54,740
So let's say const email equals req.body.email.
17
00:00:58,920 --> 00:01:02,070
Okay, and now eslint gives us this warning,
18
00:01:02,070 --> 00:01:04,160
or this error actually, and it says
19
00:01:04,160 --> 00:01:07,080
that we should use object destructuring, okay?
20
00:01:07,080 --> 00:01:09,620
And so I let this happen here on purpose
21
00:01:09,620 --> 00:01:12,620
just so that I can show you how we can do it
22
00:01:12,620 --> 00:01:14,950
with ES6 destructuring.
23
00:01:14,950 --> 00:01:18,490
And I think I talked about this before in the course,
24
00:01:18,490 --> 00:01:20,930
and I also hope that you're already familiar
25
00:01:20,930 --> 00:01:23,330
with the concept, but anyway,
26
00:01:23,330 --> 00:01:25,430
since the name of this property here
27
00:01:25,430 --> 00:01:27,920
is the same as the variable name,
28
00:01:27,920 --> 00:01:30,260
we can simply do it like this
29
00:01:30,260 --> 00:01:34,150
and get rid of the property name here, okay?
30
00:01:34,150 --> 00:01:36,520
And also we want to get the password.
31
00:01:36,520 --> 00:01:37,930
And so that would be the same,
32
00:01:37,930 --> 00:01:42,470
so basically password equals to a request.body.password.
33
00:01:42,470 --> 00:01:43,647
And instead of doing that,
34
00:01:43,647 --> 00:01:47,940
we can simply do email and password.
35
00:01:47,940 --> 00:01:50,250
And so just like this, we basically create
36
00:01:50,250 --> 00:01:54,480
these two variables of the body object, okay?
37
00:01:54,480 --> 00:01:56,380
So basically this is how the user
38
00:01:56,380 --> 00:02:00,223
is gonna send in the login credentials for us to check.
39
00:02:01,070 --> 00:02:04,130
Okay, and that check process has a couple of steps,
40
00:02:04,130 --> 00:02:05,830
and so let's actually lay them out here
41
00:02:05,830 --> 00:02:07,750
before we start coding.
42
00:02:07,750 --> 00:02:12,030
So first we need to check if email
43
00:02:12,030 --> 00:02:17,030
and passwords actually exist, all right?
44
00:02:17,900 --> 00:02:22,900
Then number two, check if the user exists,
45
00:02:24,440 --> 00:02:29,440
and at the same time if the password is correct.
46
00:02:31,960 --> 00:02:33,943
And then third, if everything is okay,
47
00:02:39,440 --> 00:02:44,440
send the token, so the JSON web token back to the client.
48
00:02:45,800 --> 00:02:48,490
Okay, so the first one is very easy.
49
00:02:48,490 --> 00:02:53,490
So if there is no email or no password,
50
00:02:56,810 --> 00:03:00,370
then we want to send an error message to our client.
51
00:03:00,370 --> 00:03:02,600
Now how are we gonna do that?
52
00:03:02,600 --> 00:03:04,490
Well we're gonna do that using the tools
53
00:03:04,490 --> 00:03:07,490
that we implemented right in the last section.
54
00:03:07,490 --> 00:03:10,730
So basically our app error, remember that?
55
00:03:10,730 --> 00:03:12,977
So we will simply create a new error here,
56
00:03:12,977 --> 00:03:15,060
and our global error handling middleware
57
00:03:15,060 --> 00:03:19,190
will then pick it up and send that error back to the client.
58
00:03:19,190 --> 00:03:22,483
And so let's actually start by importing that error.
59
00:03:23,350 --> 00:03:25,260
So remember it's this one here
60
00:03:25,260 --> 00:03:28,463
from our AppError class, right?
61
00:03:29,620 --> 00:03:34,620
So let's say AppError, and then require.
62
00:03:40,860 --> 00:03:44,150
So one level up from here, then in the utilities,
63
00:03:44,150 --> 00:03:45,050
and then appError.
64
00:03:48,990 --> 00:03:52,430
Okay, and so we need to call the next middleware,
65
00:03:52,430 --> 00:03:56,403
and then this is where we pass in the error, remember that?
66
00:03:57,260 --> 00:04:00,363
So new AppError, and the message is:
67
00:04:02,510 --> 00:04:07,510
please provide email and password.
68
00:04:07,530 --> 00:04:12,530
And the HTTP error code is 400 for bad request, okay?
69
00:04:12,720 --> 00:04:14,340
And now I've got some errors here,
70
00:04:14,340 --> 00:04:19,089
and so that again is eslint helping me to fix some bugs.
71
00:04:19,089 --> 00:04:20,709
So I see that up here, again,
72
00:04:20,709 --> 00:04:24,010
I used it with a T instead of D,
73
00:04:24,010 --> 00:04:27,740
and if I save it now, everything is correct.
74
00:04:27,740 --> 00:04:32,393
Okay, and so let's actually start testing this right away.
75
00:04:33,330 --> 00:04:34,700
And for that I will simply start
76
00:04:34,700 --> 00:04:39,700
by creating a fake token here for now, okay.
77
00:04:39,930 --> 00:04:43,287
And so then let's say res.status 200 for okay.
78
00:04:51,202 --> 00:04:53,573
JSON, and then of course, as always,
79
00:04:56,540 --> 00:05:01,010
the status set to success, and then also our token.
80
00:05:01,010 --> 00:05:02,870
And that's actually all that we're gonna send
81
00:05:02,870 --> 00:05:05,130
as a response to the login, okay?
82
00:05:05,130 --> 00:05:08,290
So no user object because that's not necessary at all.
83
00:05:08,290 --> 00:05:10,800
All we want as a response for logging in
84
00:05:10,800 --> 00:05:12,140
is actually the token.
85
00:05:12,140 --> 00:05:15,033
That's all that matters when the user logs in.
86
00:05:16,210 --> 00:05:18,960
Next up, we need to implement the route,
87
00:05:18,960 --> 00:05:23,600
so let's do that again in our user router, okay?
88
00:05:23,600 --> 00:05:27,000
And this one is actually pretty similar to this one.
89
00:05:27,000 --> 00:05:30,310
Let's just duplicate it and then replace signup
90
00:05:30,310 --> 00:05:34,780
in both instances here with login, okay?
91
00:05:34,780 --> 00:05:38,220
And again, this is only valid for a post request,
92
00:05:38,220 --> 00:05:40,360
because of course we want to send in
93
00:05:40,360 --> 00:05:43,200
the login credentials in the body.
94
00:05:43,200 --> 00:05:44,630
And so again it's a post,
95
00:05:44,630 --> 00:05:47,610
but not a get, not a patch, and not a delete,
96
00:05:47,610 --> 00:05:50,393
because that doesn't make any sense in this case.
97
00:05:51,590 --> 00:05:54,033
So let's test it right away.
98
00:05:54,970 --> 00:05:57,033
I'll copy this URL here as well.
99
00:05:58,050 --> 00:06:03,050
It's gonna be post, login,
100
00:06:03,570 --> 00:06:05,140
and then the body of course.
101
00:06:05,140 --> 00:06:08,700
So again, raw and JSON.
102
00:06:08,700 --> 00:06:11,443
So let's create a simple body here.
103
00:06:17,680 --> 00:06:19,960
All right, and so let's try to send this
104
00:06:19,960 --> 00:06:22,993
without any password, and see what happens.
105
00:06:24,460 --> 00:06:27,470
And indeed it works, so we get our message here:
106
00:06:27,470 --> 00:06:30,030
please provide email and password.
107
00:06:30,030 --> 00:06:31,820
And again, since we're in development,
108
00:06:31,820 --> 00:06:34,110
we're getting all of this error stack here,
109
00:06:34,110 --> 00:06:36,910
and the complete error with our status code,
110
00:06:36,910 --> 00:06:39,350
the status, and also of course saying
111
00:06:39,350 --> 00:06:41,330
that it is an operational error.
112
00:06:41,330 --> 00:06:45,840
So just like we defined in the previous section, okay?
113
00:06:45,840 --> 00:06:48,433
Now let's try the same with the password.
114
00:06:50,750 --> 00:06:55,750
So password, set it to I think this was the one,
115
00:06:56,400 --> 00:06:58,893
and then get rid of the email.
116
00:07:00,590 --> 00:07:02,950
And that of course triggers the same.
117
00:07:02,950 --> 00:07:06,000
Okay, and with everything correct that should then work,
118
00:07:06,000 --> 00:07:08,803
and indeed we get our fake token here.
119
00:07:10,300 --> 00:07:12,890
Now just one thing that we should do here
120
00:07:12,890 --> 00:07:14,880
is to also return.
121
00:07:14,880 --> 00:07:16,790
So we did that many times before,
122
00:07:16,790 --> 00:07:18,680
and let me explain it again.
123
00:07:18,680 --> 00:07:21,610
It's simply because after calling the next middleware,
124
00:07:21,610 --> 00:07:24,380
we want to make sure that this login function here
125
00:07:24,380 --> 00:07:27,873
finishes right away, all right?
126
00:07:30,260 --> 00:07:32,080
And since we didn't have that before,
127
00:07:32,080 --> 00:07:34,560
you now see this error here again.
128
00:07:34,560 --> 00:07:38,060
So this is already kind of familiar at this point, right?
129
00:07:38,060 --> 00:07:40,940
So cannot set headers after they are send to the client,
130
00:07:40,940 --> 00:07:43,360
because again, we sent two responses.
131
00:07:43,360 --> 00:07:47,840
First the error response, and then also this code here run,
132
00:07:47,840 --> 00:07:50,040
which of course shouldn't have done.
133
00:07:50,040 --> 00:07:52,933
And so again we use return here to fix that.
134
00:07:53,790 --> 00:07:57,430
Okay, next up, let's check if there actually is a user
135
00:07:57,430 --> 00:07:59,870
for the email that was posted.
136
00:07:59,870 --> 00:08:04,870
So const user, and so let's now use the findOne actually,
137
00:08:09,940 --> 00:08:13,400
because this time we're not selecting a user by the ID,
138
00:08:13,400 --> 00:08:16,650
but instead by its email, right?
139
00:08:16,650 --> 00:08:19,460
And so we need to pass in that filter object
140
00:08:19,460 --> 00:08:24,190
where we can say email equal to email, okay?
141
00:08:24,190 --> 00:08:25,940
So the field is called email,
142
00:08:25,940 --> 00:08:28,270
and the variable is also called email.
143
00:08:28,270 --> 00:08:32,163
And so in ES6 we can abbreviate that simply as this.
144
00:08:33,059 --> 00:08:34,490
Now before we move on here,
145
00:08:34,490 --> 00:08:36,110
there's actually something important
146
00:08:36,110 --> 00:08:38,520
that I need to do for security.
147
00:08:38,520 --> 00:08:41,220
So let me show that to you in Postman,
148
00:08:41,220 --> 00:08:43,970
where we signed up for a new account.
149
00:08:43,970 --> 00:08:46,540
And so you see here that in the user output,
150
00:08:46,540 --> 00:08:49,810
we actually get the password, okay?
151
00:08:49,810 --> 00:08:52,010
It is encrypted actually, but still,
152
00:08:52,010 --> 00:08:55,010
it's not a good practice to leak the password data
153
00:08:55,010 --> 00:08:57,710
out to the client, okay?
154
00:08:57,710 --> 00:09:01,090
For example, if we had our get all users here,
155
00:09:01,090 --> 00:09:03,480
and this route is not yet implemented,
156
00:09:03,480 --> 00:09:07,170
but if we were to get all the users from the collection,
157
00:09:07,170 --> 00:09:09,440
then all of them would have the password visible,
158
00:09:09,440 --> 00:09:12,720
and we don't want that, okay?
159
00:09:12,720 --> 00:09:15,790
And so fixing it is actually quite easy,
160
00:09:15,790 --> 00:09:17,850
because we did it before.
161
00:09:17,850 --> 00:09:19,973
All we have to do is to say password,
162
00:09:20,820 --> 00:09:25,270
and then select and set it to false.
163
00:09:25,270 --> 00:09:28,100
And so like this it will automatically never show up
164
00:09:28,100 --> 00:09:29,123
in any output.
165
00:09:30,520 --> 00:09:32,520
And to let me actually prove that to you
166
00:09:32,520 --> 00:09:37,023
by signing up as something else, so like this.
167
00:09:39,070 --> 00:09:41,920
And let's see, oh, actually we already have a user
168
00:09:41,920 --> 00:09:45,833
with that email, so let's just do test3.
169
00:09:47,300 --> 00:09:50,830
And now the password is actually still here,
170
00:09:50,830 --> 00:09:54,100
but I guess that is simply because we could just create it,
171
00:09:54,100 --> 00:09:55,610
this new document here,
172
00:09:55,610 --> 00:09:58,030
and so therefore it's not really selecting it
173
00:09:58,030 --> 00:10:01,460
because we're not actually reading it from the database.
174
00:10:01,460 --> 00:10:03,250
So let's just very quickly
175
00:10:03,250 --> 00:10:05,100
actually implement this route here,
176
00:10:05,100 --> 00:10:07,690
that's only gonna take a minute.
177
00:10:07,690 --> 00:10:10,300
So just to see if this here actually works.
178
00:10:10,300 --> 00:10:12,230
Because this step is actually important
179
00:10:12,230 --> 00:10:15,170
for what we're gonna do next, okay?
180
00:10:15,170 --> 00:10:18,820
So let's actually go ahead and copy this code
181
00:10:18,820 --> 00:10:22,000
from the getAllTours, and not really copy,
182
00:10:22,000 --> 00:10:25,133
but what we're gonna do is quite similar to this of course.
183
00:10:26,750 --> 00:10:28,590
So I'm simply gonna copy this,
184
00:10:28,590 --> 00:10:30,450
but without the API features.
185
00:10:30,450 --> 00:10:33,700
So I'm not really interested in that, okay?
186
00:10:33,700 --> 00:10:35,500
And so this one I'm actually gonna do
187
00:10:35,500 --> 00:10:39,170
in the user controller, because getting all the users
188
00:10:39,170 --> 00:10:41,350
has nothing to do with authentication.
189
00:10:41,350 --> 00:10:43,570
And so in this case the user controller
190
00:10:43,570 --> 00:10:47,020
is the perfect place for doing this.
191
00:10:47,020 --> 00:10:49,440
Now of course I also need to quickly import
192
00:10:49,440 --> 00:10:51,990
the user model here, and so let's also copy that
193
00:10:51,990 --> 00:10:56,580
from the tourController, which is not the same but similar.
194
00:10:56,580 --> 00:11:00,550
So let's grab actually all of this
195
00:11:04,200 --> 00:11:06,370
into our user controller.
196
00:11:06,370 --> 00:11:09,683
This one we don't need, but we also need to catchAsync.
197
00:11:10,520 --> 00:11:13,640
Okay, so tour is gonna be user,
198
00:11:13,640 --> 00:11:18,400
and here it will be userModel, all right?
199
00:11:18,400 --> 00:11:21,420
Then here we have tours, and down here and down here,
200
00:11:21,420 --> 00:11:23,790
so I hit Command + D to select all of them
201
00:11:23,790 --> 00:11:26,033
and change it to users.
202
00:11:27,190 --> 00:11:32,190
And then here of course what we are awaiting is User.find.
203
00:11:34,870 --> 00:11:36,320
Now since we have an await here,
204
00:11:36,320 --> 00:11:41,310
we need async, then we also need next,
205
00:11:41,310 --> 00:11:42,810
and since we have an async here,
206
00:11:42,810 --> 00:11:46,580
we should then wrap the entire thing into a catch async.
207
00:11:46,580 --> 00:11:47,713
So let's do that.
208
00:11:50,090 --> 00:11:51,700
Okay, and so at this point
209
00:11:51,700 --> 00:11:53,810
this is nothing new to you anymore,
210
00:11:53,810 --> 00:11:58,120
we're already used to doing this kind of stuff, right?
211
00:11:58,120 --> 00:12:00,670
So, this should already work at this point,
212
00:12:00,670 --> 00:12:02,470
so let's try it out.
213
00:12:02,470 --> 00:12:06,460
So get all users, and now indeed we see
214
00:12:06,460 --> 00:12:10,030
that their password is not included in the output.
215
00:12:10,030 --> 00:12:13,853
And that is important because actually, in the find,
216
00:12:15,090 --> 00:12:17,093
so back here in the AuthController,
217
00:12:18,030 --> 00:12:21,490
this here will now also not contain the password, okay?
218
00:12:21,490 --> 00:12:23,060
And so the output of this here
219
00:12:23,060 --> 00:12:25,920
will now also not contain the password.
220
00:12:25,920 --> 00:12:28,890
But we do need the password in order to check
221
00:12:28,890 --> 00:12:30,810
if it is correct, right?
222
00:12:30,810 --> 00:12:34,500
And so we need to explicitly select it as well.
223
00:12:34,500 --> 00:12:37,460
So remember how we used select before
224
00:12:37,460 --> 00:12:40,150
to basically simply select a couple of fields
225
00:12:40,150 --> 00:12:43,450
from the database, only the ones that we needed?
226
00:12:43,450 --> 00:12:45,460
Now in this case, when we want the field
227
00:12:45,460 --> 00:12:47,640
that is by default not selected,
228
00:12:47,640 --> 00:12:50,853
we need to user plus and then the name of the field.
229
00:12:51,720 --> 00:12:53,610
So password in this case.
230
00:12:53,610 --> 00:12:58,220
And so like this, it will be back in the output, okay?
231
00:12:58,220 --> 00:13:01,750
Of course we need to await this query,
232
00:13:01,750 --> 00:13:06,260
and then mark the function as async.
233
00:13:06,260 --> 00:13:08,140
And then just like before,
234
00:13:08,140 --> 00:13:12,010
in order to avoid that ugly try catch block,
235
00:13:12,010 --> 00:13:16,253
wrap this entire function into catchAsync.
236
00:13:18,520 --> 00:13:20,163
All right, makes sense?
237
00:13:22,170 --> 00:13:26,770
So let's now quickly just log the user to the console,
238
00:13:26,770 --> 00:13:28,353
just to see if it works.
239
00:13:32,220 --> 00:13:34,033
So this one here.
240
00:13:35,460 --> 00:13:39,600
We get our success, and indeed we get the user here.
241
00:13:39,600 --> 00:13:42,650
So with exactly the email that I just posted,
242
00:13:42,650 --> 00:13:45,830
and then the password is now also back to being included
243
00:13:45,830 --> 00:13:47,890
in the output, all right?
244
00:13:47,890 --> 00:13:51,453
And so again, that's because we explicitly selected it here.
245
00:13:52,490 --> 00:13:54,950
And so now it's time to actually compare
246
00:13:54,950 --> 00:13:57,400
the passwords that we have in the database
247
00:13:57,400 --> 00:13:59,830
with the one that the user just posted.
248
00:13:59,830 --> 00:14:01,930
But how are we gonna do that?
249
00:14:01,930 --> 00:14:05,190
Because for example, the password might be,
250
00:14:05,190 --> 00:14:09,169
or is in this example, pass1234, but the one
251
00:14:09,169 --> 00:14:13,983
that we have stored in the document looks like this.
252
00:14:15,040 --> 00:14:17,220
So how are we gonna compare this?
253
00:14:17,220 --> 00:14:19,960
There's not really a way of doing it, right?
254
00:14:19,960 --> 00:14:22,300
But actually there is, all we have to do
255
00:14:22,300 --> 00:14:25,890
is to again use the bcrypt package, okay?
256
00:14:25,890 --> 00:14:29,400
So we used bcrypt to generate this hashed password,
257
00:14:29,400 --> 00:14:31,230
and we can also use the same package
258
00:14:31,230 --> 00:14:34,930
to basically compare an original password like this here
259
00:14:34,930 --> 00:14:36,283
with the hashed password.
260
00:14:37,230 --> 00:14:40,700
Of course this password here, since it's encrypted,
261
00:14:40,700 --> 00:14:43,350
there's no way of getting back the old,
262
00:14:43,350 --> 00:14:46,680
so the original password from this string, right?
263
00:14:46,680 --> 00:14:48,150
So that's the entire point
264
00:14:48,150 --> 00:14:50,550
of actually encrypting a password.
265
00:14:50,550 --> 00:14:52,410
And so the only way of doing it
266
00:14:52,410 --> 00:14:54,890
is for this package for this algorithm
267
00:14:54,890 --> 00:14:58,100
to actually encrypt this password as well,
268
00:14:58,100 --> 00:15:02,210
and then compare it with the encrypted one, all right?
269
00:15:02,210 --> 00:15:05,110
So let's implement a function that's gonna do that,
270
00:15:05,110 --> 00:15:08,350
and for that we will use, again, the bcrypt package.
271
00:15:08,350 --> 00:15:11,280
And we will do that in the user model.
272
00:15:11,280 --> 00:15:13,767
And you might ask "Why we're doing it in a model
273
00:15:13,767 --> 00:15:16,310
"and not just here," but that's, again,
274
00:15:16,310 --> 00:15:19,730
because this is really related to the data itself.
275
00:15:19,730 --> 00:15:22,930
And also we already have that package in there,
276
00:15:22,930 --> 00:15:26,090
and so it's easier to simply do it there.
277
00:15:26,090 --> 00:15:28,663
So let's just get rid of this string,
278
00:15:30,600 --> 00:15:32,360
and then create a function here,
279
00:15:32,360 --> 00:15:34,580
which will check if the given password
280
00:15:34,580 --> 00:15:37,473
is the same as the one stored in the document.
281
00:15:38,520 --> 00:15:41,100
So for the first time now we're gonna create something
282
00:15:41,100 --> 00:15:43,000
called an instance method.
283
00:15:43,000 --> 00:15:46,120
So an instance method is basically a method
284
00:15:46,120 --> 00:15:48,500
that is gonna be available on all documents
285
00:15:48,500 --> 00:15:50,843
of a certain collection, okay?
286
00:15:51,680 --> 00:15:53,320
And it works like this.
287
00:15:53,320 --> 00:15:56,120
So again, it's defined on a userSchema,
288
00:15:56,120 --> 00:16:01,050
and then we say methods, and now in this case
289
00:16:01,050 --> 00:16:05,273
we want to call the function correctPassword, all right?
290
00:16:10,340 --> 00:16:12,810
So function, now this function is gonna accept
291
00:16:12,810 --> 00:16:14,470
a candidatePassword, so the password
292
00:16:17,734 --> 00:16:19,650
that the user passes in the body,
293
00:16:19,650 --> 00:16:22,347
and then also the userPassword, okay?
294
00:16:26,010 --> 00:16:28,590
Now inside of these instanced methods,
295
00:16:28,590 --> 00:16:31,470
since they are available on the document,
296
00:16:31,470 --> 00:16:35,430
the this keyword actually points to the current document.
297
00:16:35,430 --> 00:16:37,610
But in this case, since we have the password
298
00:16:37,610 --> 00:16:42,080
set to select false, so this here, remember?
299
00:16:42,080 --> 00:16:43,690
Okay, and because of that,
300
00:16:43,690 --> 00:16:47,920
this.password will not be available.
301
00:16:47,920 --> 00:16:50,780
So ideally we would do it like this,
302
00:16:50,780 --> 00:16:52,360
and so this way we would only need
303
00:16:52,360 --> 00:16:56,130
to pass in the candidatePassword and not the userPassword.
304
00:16:56,130 --> 00:16:58,690
But again, right now that's not possible
305
00:16:58,690 --> 00:17:02,350
because the password is not available in the output.
306
00:17:02,350 --> 00:17:03,420
And so that's why we actually
307
00:17:03,420 --> 00:17:06,380
have to pass in userPassword as well.
308
00:17:06,380 --> 00:17:07,890
So the goal of this function
309
00:17:07,890 --> 00:17:11,030
is to really only return true or false.
310
00:17:11,030 --> 00:17:14,000
So basically true if the passwords are the same,
311
00:17:14,000 --> 00:17:15,663
and false if not.
312
00:17:16,560 --> 00:17:21,410
So return, and then bcrypt which we already know,
313
00:17:21,410 --> 00:17:26,257
and then we are gonna use the compare function, okay?
314
00:17:26,257 --> 00:17:29,190
And the compare function is really easy,
315
00:17:29,190 --> 00:17:32,200
all we need is to pass in the candidatePassword
316
00:17:32,200 --> 00:17:37,060
and the userPassword, not userSchema, userPassword, okay?
317
00:17:39,270 --> 00:17:42,090
And just like the hash function up here,
318
00:17:42,090 --> 00:17:45,383
this one is also an asynchronous function.
319
00:17:46,270 --> 00:17:50,973
And so just like before we use await, and then here async.
320
00:17:53,330 --> 00:17:54,940
Okay, make sense?
321
00:17:54,940 --> 00:17:57,630
So again, this compare function here
322
00:17:57,630 --> 00:17:59,800
will very simply return true
323
00:17:59,800 --> 00:18:04,470
if these two passwords here are the same, and false if not.
324
00:18:04,470 --> 00:18:07,030
And again, we cannot compare them manually
325
00:18:07,030 --> 00:18:10,020
because the candidate password is not hashed,
326
00:18:10,020 --> 00:18:12,800
so it's the original password coming from the user,
327
00:18:12,800 --> 00:18:15,580
but userPassword is of course hashed,
328
00:18:15,580 --> 00:18:18,230
and so without this function here
329
00:18:18,230 --> 00:18:21,830
we would have no way of comparing them, okay?
330
00:18:21,830 --> 00:18:23,990
So here we return true or false,
331
00:18:23,990 --> 00:18:26,893
now all we need to do is to actually call this function
332
00:18:26,893 --> 00:18:28,633
in the authController.
333
00:18:29,920 --> 00:18:31,873
Let's close a couple of these.
334
00:18:34,080 --> 00:18:38,253
All right, so this here was only here for demonstration.
335
00:18:41,400 --> 00:18:43,563
So let's simply call this here correct,
336
00:18:44,400 --> 00:18:47,110
and now remember that the function that we just defined
337
00:18:47,110 --> 00:18:48,670
is an instanced method.
338
00:18:48,670 --> 00:18:52,260
And so therefore it is available on all the user documents.
339
00:18:52,260 --> 00:18:54,780
And so this variable here right now
340
00:18:54,780 --> 00:18:57,050
is a user document, right?
341
00:18:57,050 --> 00:19:00,270
Because it's a result of querying the user model.
342
00:19:00,270 --> 00:19:03,637
And so we can now say user.correctPassword.
343
00:19:06,760 --> 00:19:10,650
Now all we need to do is pass in the candidate password,
344
00:19:10,650 --> 00:19:13,020
which is password, remember.
345
00:19:13,020 --> 00:19:17,830
So this one here, and then the userPassword.
346
00:19:17,830 --> 00:19:22,830
And so that's in user.password, all right?
347
00:19:23,450 --> 00:19:26,373
And so this here will now be either true or false.
348
00:19:27,990 --> 00:19:30,810
All right, and now let's actually use these two variables
349
00:19:30,810 --> 00:19:33,500
in order to figure out if the user exists
350
00:19:33,500 --> 00:19:35,200
and the password is correct.
351
00:19:35,200 --> 00:19:36,710
So we already figured that out,
352
00:19:36,710 --> 00:19:40,390
but now we need to actually write our if statement.
353
00:19:40,390 --> 00:19:45,390
So if there is no user, or the password is incorrect,
354
00:19:46,160 --> 00:19:49,853
so basically correct is false, which is what this means.
355
00:19:50,860 --> 00:19:54,590
In that case, we want to, again,
356
00:19:54,590 --> 00:19:58,640
return and go straight to our next middleware
357
00:19:58,640 --> 00:19:59,640
with a new AppError.
358
00:20:00,980 --> 00:20:05,973
And in this case saying incorrect email or password, okay?
359
00:20:08,990 --> 00:20:11,560
And then the status code is 401,
360
00:20:11,560 --> 00:20:14,870
which means unauthorized, all right?
361
00:20:14,870 --> 00:20:16,910
Now we could've done this separately,
362
00:20:16,910 --> 00:20:18,847
so first checking for the user,
363
00:20:18,847 --> 00:20:21,440
and then checking for the correct password.
364
00:20:21,440 --> 00:20:24,600
But in that case we would then give a potential attacker
365
00:20:24,600 --> 00:20:28,710
information whether the email or the password is incorrect.
366
00:20:28,710 --> 00:20:31,550
And this way here it's a bit more vague.
367
00:20:31,550 --> 00:20:34,830
So we're not really specifying what is incorrect here.
368
00:20:34,830 --> 00:20:37,060
So if it's email or if it's the password.
369
00:20:37,060 --> 00:20:38,700
And so if there's some attacker
370
00:20:38,700 --> 00:20:41,150
trying to put in some random data,
371
00:20:41,150 --> 00:20:43,640
then they will not know if the email actually exists,
372
00:20:43,640 --> 00:20:47,143
or if it's just the password that's wrong, all right?
373
00:20:47,990 --> 00:20:50,860
Now just two things here, and the first one
374
00:20:50,860 --> 00:20:53,140
is that we actually need to await
375
00:20:53,140 --> 00:20:55,480
this asynchronous function, okay?
376
00:20:55,480 --> 00:20:57,470
So remember that correct password
377
00:20:57,470 --> 00:20:59,000
is an asynchronous function,
378
00:20:59,000 --> 00:21:01,333
and so here we also need to await for that.
379
00:21:02,690 --> 00:21:04,530
And then also there's another problem,
380
00:21:04,530 --> 00:21:06,980
because of this user doesn't exist here,
381
00:21:06,980 --> 00:21:10,950
then this next line of code cannot really run, okay?
382
00:21:10,950 --> 00:21:13,550
Because for example, user.password
383
00:21:13,550 --> 00:21:15,400
is not gonna be available.
384
00:21:15,400 --> 00:21:18,800
And so we actually need to move all of this,
385
00:21:18,800 --> 00:21:20,690
or actually only this code,
386
00:21:20,690 --> 00:21:24,343
we're gonna move it here into the if else statement.
387
00:21:26,740 --> 00:21:29,000
All right, and so this way,
388
00:21:29,000 --> 00:21:32,550
if the user does not exist, so if this is true,
389
00:21:32,550 --> 00:21:34,900
well then it will not even run this code here,
390
00:21:34,900 --> 00:21:37,070
and then there's not gonna be any problem.
391
00:21:37,070 --> 00:21:40,510
But if the user exists, then it will also run this code
392
00:21:40,510 --> 00:21:43,600
and check if the password is actually right.
393
00:21:43,600 --> 00:21:45,520
And so if the password is correct,
394
00:21:45,520 --> 00:21:50,010
only in that case we ever reach this piece of code here.
395
00:21:50,010 --> 00:21:52,710
So that's the whole idea of this function.
396
00:21:52,710 --> 00:21:55,030
So basically we check for the negatives.
397
00:21:55,030 --> 00:21:57,270
So if there's no email and no password,
398
00:21:57,270 --> 00:21:58,880
then we get this error.
399
00:21:58,880 --> 00:22:01,690
If there's no user, or if there's a wrong password,
400
00:22:01,690 --> 00:22:03,540
then create this error.
401
00:22:03,540 --> 00:22:05,610
But if there was no error at all,
402
00:22:05,610 --> 00:22:09,060
well in that case we reach this part of the code,
403
00:22:09,060 --> 00:22:10,820
where we now generate a token
404
00:22:10,820 --> 00:22:13,490
and then send it back to the user.
405
00:22:13,490 --> 00:22:16,740
Now creating this token is gonna be the exact same thing
406
00:22:16,740 --> 00:22:18,500
as we did before here.
407
00:22:18,500 --> 00:22:20,780
And so instead of repeating all of this code,
408
00:22:20,780 --> 00:22:24,210
let's actually create a function for this, okay?
409
00:22:24,210 --> 00:22:25,840
So I'm gonna copy this code,
410
00:22:25,840 --> 00:22:29,427
and then here very quickly const signToken,
411
00:22:31,900 --> 00:22:36,090
which is gonna receive as the only input the user ID.
412
00:22:36,090 --> 00:22:41,090
So ID, and it will then return the token, okay?
413
00:22:43,370 --> 00:22:46,793
So it will simply sign this and return it right away.
414
00:22:47,700 --> 00:22:50,920
All right, and so here what we're gonna do
415
00:22:50,920 --> 00:22:55,920
is signToken and pass in this ID.
416
00:23:04,970 --> 00:23:09,330
And then of course we also need to change it up here, okay?
417
00:23:09,330 --> 00:23:11,750
So set this ID to this ID,
418
00:23:11,750 --> 00:23:14,893
which as you already know at this point is the same as this.
419
00:23:15,950 --> 00:23:19,763
All right, and so let's now go ahead and do the same here.
420
00:23:22,547 --> 00:23:26,340
signToken, and then in this case it is user._id.
421
00:23:31,300 --> 00:23:33,910
Phew, that was a long lecture,
422
00:23:33,910 --> 00:23:37,090
let's now go ahead and try it out.
423
00:23:37,090 --> 00:23:38,363
So it should now work.
424
00:23:39,250 --> 00:23:43,470
So remember, well this is now another user,
425
00:23:43,470 --> 00:23:46,030
but I know that this is the password that I used.
426
00:23:46,030 --> 00:23:48,580
So let's for now let's use another one,
427
00:23:48,580 --> 00:23:52,003
so just test12, and let's see what happens.
428
00:23:53,540 --> 00:23:57,450
Let's wait, and indeed, incorrect email or password.
429
00:23:57,450 --> 00:24:00,230
And so we get of course also our 401,
430
00:24:00,230 --> 00:24:04,600
and indeed it means that our code is currently testing
431
00:24:04,600 --> 00:24:05,933
for the password already.
432
00:24:06,780 --> 00:24:10,230
So if we now choose the correct password,
433
00:24:10,230 --> 00:24:12,793
then it should pass, so let's wait for it.
434
00:24:13,760 --> 00:24:16,760
But, we still get this error.
435
00:24:16,760 --> 00:24:20,453
Well, so let's simply get rid of all of our users here,
436
00:24:22,170 --> 00:24:24,420
just to make sure that it doesn't have to do anything
437
00:24:24,420 --> 00:24:28,740
with the users, and then create a new one, all right.
438
00:24:33,080 --> 00:24:37,473
So hello@jonas, and pass1234.
439
00:24:38,710 --> 00:24:42,373
Let's go ahead and copy it, I will send it now.
440
00:24:46,800 --> 00:24:50,070
And so these credentials are now correct for sure.
441
00:24:50,070 --> 00:24:52,760
So if it doesn't work now there's some kind of bug.
442
00:24:52,760 --> 00:24:55,870
But now actually it worked, great.
443
00:24:55,870 --> 00:25:00,090
So here is our token, and it looks exactly like before,
444
00:25:00,090 --> 00:25:02,483
so we can assume that it is correct.
445
00:25:03,570 --> 00:25:06,333
Now let's now try it again, deleting this, okay.
446
00:25:07,810 --> 00:25:10,753
And so with the wrong password it does not work.
447
00:25:11,890 --> 00:25:15,423
Let's now put the password right and the email wrong,
448
00:25:18,230 --> 00:25:19,730
and then we get the same error.
449
00:25:19,730 --> 00:25:21,883
So incorrect email or password.
450
00:25:22,930 --> 00:25:25,560
And again if we put everything back,
451
00:25:25,560 --> 00:25:27,560
then we get a new token.
452
00:25:27,560 --> 00:25:30,810
And so we are now really logged into the application.
453
00:25:30,810 --> 00:25:33,580
And I know this might look kind of abstract,
454
00:25:33,580 --> 00:25:37,340
so all we really get is a token, and then that means
455
00:25:37,340 --> 00:25:40,020
we are logged into the application, right?
456
00:25:40,020 --> 00:25:44,720
But, well, that's how it works on stateless authentication.
457
00:25:44,720 --> 00:25:47,810
Later on when we really build the dynamic website,
458
00:25:47,810 --> 00:25:50,190
then of course it's gonna be a lot more visible
459
00:25:50,190 --> 00:25:53,900
if the user is either logged in or logged out, right?
460
00:25:53,900 --> 00:25:55,920
But it will still work behind the scenes
461
00:25:55,920 --> 00:25:57,670
using this same token.
462
00:25:57,670 --> 00:26:01,560
So if there's no token, then the website will look one way,
463
00:26:01,560 --> 00:26:03,800
and if there is a token then the website's
464
00:26:03,800 --> 00:26:06,630
gonna look another way, with the user image
465
00:26:06,630 --> 00:26:11,150
and the username right there in the website, for example.
466
00:26:11,150 --> 00:26:13,373
Anyway, this was quite a long lecture.
467
00:26:14,370 --> 00:26:17,100
Make sure to go back here and really try to understand
468
00:26:17,100 --> 00:26:20,210
all of this code that we have here, all right?
469
00:26:20,210 --> 00:26:21,870
Because I know that some of this
470
00:26:21,870 --> 00:26:23,660
might be a bit confusing.
471
00:26:23,660 --> 00:26:26,963
For example, this correctPassword function here.
472
00:26:27,850 --> 00:26:30,933
And then I'm sure everything will make sense to you.
38003
Can't find what you're looking for?
Get subtitles in any language from opensubtitles.com, and translate them here.