1
00:00:02,020 --> 00:00:04,880
So we did now implement user signup.

2
00:00:04,880 --> 00:00:08,300
The next step now is to implement user login

3
00:00:08,300 --> 00:00:11,310
so that users can submit their login form

4
00:00:11,310 --> 00:00:14,540
and you then, well, do what?

5
00:00:14,540 --> 00:00:16,540
Well, that's the big question.

6
00:00:16,540 --> 00:00:20,540
How do we now continue with our authentication?

7
00:00:20,540 --> 00:00:22,940
Well, in the end, when a user logs in

8
00:00:22,940 --> 00:00:26,260
and entered an email and password on the server,

9
00:00:26,260 --> 00:00:29,780
we wanna take that entered data and verify it.

10
00:00:29,780 --> 00:00:31,960
We wanna check if we find a user

11
00:00:31,960 --> 00:00:34,580
with that email address in our database,

12
00:00:34,580 --> 00:00:35,710
because if we don't,

13
00:00:35,710 --> 00:00:38,120
the user certainly won't be able to log in

14
00:00:38,120 --> 00:00:41,540
because there is no account with that email address.

15
00:00:41,540 --> 00:00:43,950
And if we found an entry in the database,

16
00:00:43,950 --> 00:00:47,280
then of course we wanna check if the password was correct

17
00:00:47,280 --> 00:00:49,660
because just having the email address alone

18
00:00:49,660 --> 00:00:51,033
is, of course, not enough.

19
00:00:51,890 --> 00:00:55,050
So now here, we got this login page

20
00:00:55,050 --> 00:00:58,790
and this login form, when it is submitted,

21
00:00:58,790 --> 00:01:02,940
leads to a post request being sent to /login.

22
00:01:02,940 --> 00:01:06,223
And that post request contains the email and the password.

23
00:01:07,330 --> 00:01:10,080
Here, I don't have a confirm email field

24
00:01:10,080 --> 00:01:12,520
because this is for logging in anyways.

25
00:01:12,520 --> 00:01:14,640
We are not creating an account here.

26
00:01:14,640 --> 00:01:16,920
We don't need to check for typos here

27
00:01:16,920 --> 00:01:20,090
because if you have a typo in your email or password,

28
00:01:20,090 --> 00:01:22,840
the login will fail anyways,

29
00:01:22,840 --> 00:01:25,340
so there's no need to add an extra check

30
00:01:25,340 --> 00:01:27,953
whether you have a typo in the email or not.

31
00:01:28,940 --> 00:01:33,940
So therefore now here in demo.js, in the login post route,

32
00:01:34,120 --> 00:01:37,190
we now want to see if we find a user

33
00:01:37,190 --> 00:01:39,040
for the provided credentials,

34
00:01:39,040 --> 00:01:41,653
so for the provided email and password.

35
00:01:42,940 --> 00:01:46,450
Hence, just as before in the signup route here,

36
00:01:46,450 --> 00:01:48,710
we can start by extracting some data

37
00:01:48,710 --> 00:01:52,863
from the incoming request body, so I'll copy this here.

38
00:01:53,790 --> 00:01:57,060
I won't extract confirm email because as I mentioned,

39
00:01:57,060 --> 00:02:00,110
this doesn't exist and matter here,

40
00:02:00,110 --> 00:02:02,683
but I do extract the password and email.

41
00:02:03,860 --> 00:02:05,870
And now the first step is to check

42
00:02:05,870 --> 00:02:08,372
whether we have a user for the given email.

43
00:02:09,410 --> 00:02:13,550
Hence, we wanna check if we got an existing user.

44
00:02:13,550 --> 00:02:16,440
And for this, we await the result of reaching out

45
00:02:16,440 --> 00:02:21,200
to our database, to the user's collection here.

46
00:02:21,200 --> 00:02:24,320
And in there, we try to find one user

47
00:02:24,320 --> 00:02:29,320
where the email should be equal to our entered email,

48
00:02:29,472 --> 00:02:32,913
enteredEmail, like this.

49
00:02:34,070 --> 00:02:36,740
So that's our logic for checking if we have a user

50
00:02:36,740 --> 00:02:39,870
with that email address in our database.

51
00:02:39,870 --> 00:02:43,720
If we don't have a user with that email in the database,

52
00:02:43,720 --> 00:02:47,220
findOne will return null or undefined.

53
00:02:47,220 --> 00:02:49,340
So it will not cause an error,

54
00:02:49,340 --> 00:02:52,163
but it also won't return a result.

55
00:02:53,230 --> 00:02:57,220
So we can add a if check and check if not existing user,

56
00:02:57,220 --> 00:02:58,870
so if data is falsey

57
00:02:58,870 --> 00:03:03,370
which it would be if findOne does return null or undefined

58
00:03:03,370 --> 00:03:06,913
because those values are treated as falsey.

59
00:03:08,020 --> 00:03:10,120
So if you don't have an existing user,

60
00:03:10,120 --> 00:03:12,060
that's what we're checking for here,

61
00:03:12,060 --> 00:03:15,380
then, of course, we can't log the user in.

62
00:03:15,380 --> 00:03:19,360
So in this case, I'll return to avoid that any other code

63
00:03:19,360 --> 00:03:21,770
thereafter gets executed.

64
00:03:21,770 --> 00:03:25,630
And I'll redirect back to the login page like this

65
00:03:25,630 --> 00:03:28,173
so that the user is able to try again.

66
00:03:29,320 --> 00:03:30,490
And here for the moment,

67
00:03:30,490 --> 00:03:34,070
I'll just console.log could not log in.

68
00:03:34,070 --> 00:03:35,930
Of course, the user won't see that,

69
00:03:35,930 --> 00:03:39,540
but it's a little info log for us as a developer

70
00:03:39,540 --> 00:03:42,113
whilst we are working on this website.

71
00:03:43,550 --> 00:03:47,090
Now let's assume we made it past this if check though.

72
00:03:47,090 --> 00:03:50,980
That means that we do have a user with that email address,

73
00:03:50,980 --> 00:03:53,820
but of course, then we still have to check if the password

74
00:03:53,820 --> 00:03:56,290
that was entered is correct.

75
00:03:56,290 --> 00:03:59,890
And for this, we can again use the bcrypt package

76
00:03:59,890 --> 00:04:01,040
because keep in mind

77
00:04:01,040 --> 00:04:03,690
that the password in the database is hashed.

78
00:04:03,690 --> 00:04:05,503
It looks something like this.

79
00:04:06,720 --> 00:04:09,750
Of course, the user hasn't entered this password.

80
00:04:09,750 --> 00:04:13,320
The user entered his or her original password.

81
00:04:13,320 --> 00:04:15,300
So now we need a way of finding out

82
00:04:15,300 --> 00:04:19,333
if that unhashed password is equal to this hashed password.

83
00:04:20,170 --> 00:04:24,700
Now, as I mentioned, the hashed password can't be decoded,

84
00:04:24,700 --> 00:04:27,150
but the bcrypt package,

85
00:04:27,150 --> 00:04:31,270
which used an internal algorithm for creating the hash,

86
00:04:31,270 --> 00:04:34,600
is able to take a raw unhashed string

87
00:04:34,600 --> 00:04:37,910
and find out if that string could lead

88
00:04:37,910 --> 00:04:39,740
to that hash we have here

89
00:04:39,740 --> 00:04:43,150
if the same algorithm would be used on it.

90
00:04:43,150 --> 00:04:45,880
So the bcrypt package is able to compare

91
00:04:45,880 --> 00:04:48,560
unhashed values to hashed values

92
00:04:48,560 --> 00:04:51,763
because it knows how it did hash the value.

93
00:04:53,290 --> 00:04:55,950
And hence here we can use bcrypt again

94
00:04:55,950 --> 00:04:58,930
and use the built-in compare function,

95
00:04:58,930 --> 00:05:00,740
which does what the name implies.

96
00:05:00,740 --> 00:05:04,430
And here, compare then wants two parameter values

97
00:05:04,430 --> 00:05:07,840
where the first value is the unhashed value

98
00:05:07,840 --> 00:05:10,650
and then the second value is the hashed value

99
00:05:10,650 --> 00:05:13,363
to which you wanna compare the unhashed value.

100
00:05:14,320 --> 00:05:16,960
So the first value here, the unhashed one,

101
00:05:16,960 --> 00:05:19,260
is the entered password.

102
00:05:19,260 --> 00:05:22,610
The second value is the password we have in the database,

103
00:05:22,610 --> 00:05:26,890
which is hashed, and we find this on our existing user.

104
00:05:26,890 --> 00:05:29,910
So here we can access existingUser.password

105
00:05:29,910 --> 00:05:33,453
and that is the hashed password stored in the database.

106
00:05:34,890 --> 00:05:39,890
Now, compare, just like hash, does return a promise.

107
00:05:40,540 --> 00:05:43,840
So here, since we already have async here,

108
00:05:43,840 --> 00:05:46,120
we awaited the database operation,

109
00:05:46,120 --> 00:05:49,080
now we also await this comparison.

110
00:05:49,080 --> 00:05:52,530
And as a result, we get a Boolean that is true

111
00:05:52,530 --> 00:05:54,340
if the passwords are equal,

112
00:05:54,340 --> 00:05:56,163
and that is false if they are not.

113
00:05:57,130 --> 00:05:59,590
So here, I'll name it passwordsAreEqual

114
00:06:01,500 --> 00:06:02,883
and store it like this.

115
00:06:04,560 --> 00:06:07,803
So this is now how we can compare passwords.

116
00:06:08,680 --> 00:06:12,580
And now I simply check if not passwords are equal,

117
00:06:12,580 --> 00:06:16,120
which means the passwords are not equal, they are different,

118
00:06:16,120 --> 00:06:19,720
in which case I will again redirect to the login page

119
00:06:19,720 --> 00:06:23,110
and return so that no other code gets executed.

120
00:06:23,110 --> 00:06:26,000
And again, I will say could not log in,

121
00:06:26,000 --> 00:06:27,000
passwords

122
00:06:28,480 --> 00:06:30,243
are not equal.

123
00:06:31,210 --> 00:06:33,310
Again, this here is just an info message

124
00:06:33,310 --> 00:06:35,093
for us, the developer.

125
00:06:36,530 --> 00:06:38,810
Now, if we made it past this if check though,

126
00:06:38,810 --> 00:06:41,840
then we know that the passwords are equal,

127
00:06:41,840 --> 00:06:44,360
so the user did enter the correct password,

128
00:06:44,360 --> 00:06:47,520
and therefore then we wanna grant access

129
00:06:47,520 --> 00:06:49,540
to protected resources.

130
00:06:49,540 --> 00:06:51,440
Now, this will be a third step

131
00:06:51,440 --> 00:06:54,170
for which we then also need sessions and cookies,

132
00:06:54,170 --> 00:06:56,140
but for the moment we at least know

133
00:06:56,140 --> 00:06:59,790
that the user is authenticated,

134
00:06:59,790 --> 00:07:03,330
and hence I'll add this info message for now.

135
00:07:03,330 --> 00:07:08,260
And for the moment, I will then simply redirect to admin,

136
00:07:08,260 --> 00:07:11,880
though I again wanna emphasize that at this point of time,

137
00:07:11,880 --> 00:07:14,210
we don't have any protection for admin

138
00:07:14,210 --> 00:07:16,330
so we could redirect to this page

139
00:07:16,330 --> 00:07:19,583
no matter if the user entered correct credentials or not.

140
00:07:21,550 --> 00:07:26,080
So therefore, if I now save everything here,

141
00:07:26,080 --> 00:07:28,720
we should be able to go to login.

142
00:07:28,720 --> 00:07:33,030
And then here, if I enter a correct email,

143
00:07:33,030 --> 00:07:36,650
but an incorrect password and I click log in,

144
00:07:36,650 --> 00:07:39,960
I'm redirected back to login and on the server side,

145
00:07:39,960 --> 00:07:44,360
I see could not log in, passwords are not equal as expected

146
00:07:44,360 --> 00:07:47,203
because I deliberately entered a wrong password.

147
00:07:48,490 --> 00:07:49,410
If, on the other hand,

148
00:07:49,410 --> 00:07:52,570
I enter an email that doesn't exist in the database

149
00:07:52,570 --> 00:07:55,070
and then any password of my choice,

150
00:07:55,070 --> 00:07:57,010
I'm also redirected back.

151
00:07:57,010 --> 00:07:59,810
This time, the message is just could not log in,

152
00:07:59,810 --> 00:08:02,310
which is the info message I am outputting

153
00:08:02,310 --> 00:08:04,260
if I couldn't find a user.

154
00:08:04,260 --> 00:08:06,010
So that's also working as expected.

155
00:08:07,670 --> 00:08:11,980
But now finally, if I do enter the correct email

156
00:08:11,980 --> 00:08:14,340
and the correct password for it,

157
00:08:14,340 --> 00:08:17,100
then I'm redirected to the admin page

158
00:08:17,100 --> 00:08:20,400
and my password manager starts and wants to save this,

159
00:08:20,400 --> 00:08:21,970
which proves that we got a working

160
00:08:21,970 --> 00:08:24,180
authentication pattern here.

161
00:08:24,180 --> 00:08:26,190
But of course, I won't save it here.

162
00:08:26,190 --> 00:08:28,360
And therefore, we succeeded.

163
00:08:28,360 --> 00:08:32,210
We did go through that login route successfully.

164
00:08:32,210 --> 00:08:33,679
Again, we're not finished.

165
00:08:33,679 --> 00:08:36,770
We're not really managing any kind of protection

166
00:08:36,770 --> 00:08:37,960
for the admin page

167
00:08:37,960 --> 00:08:41,789
and we're not tracking the user's authentication status,

168
00:08:41,789 --> 00:08:45,283
but we at least validated those credentials.

