1
00:00:00,000 --> 00:00:03,000
So, let's in a log in server action.

2
00:00:03,000 --> 00:00:06,000
For that I'll go to auth-actions.js.

3
00:00:06,000 --> 00:00:09,000
And here at the bottom of the file, for example,

4
00:00:09,000 --> 00:00:13,000
I'll export a new async function called login.

5
00:00:16,000 --> 00:00:19,000
And here, I also expect to get a previous state

6
00:00:19,000 --> 00:00:21,000
since this server action function

7
00:00:21,000 --> 00:00:25,000
will also be set as a value for use form state.

8
00:00:26,000 --> 00:00:28,000
And I'll expect to get the formData,

9
00:00:29,000 --> 00:00:31,000
so exactly the same parameters

10
00:00:31,000 --> 00:00:35,000
as we get on the signup server action.

11
00:00:36,000 --> 00:00:39,000
Therefore, we can of course also retrieve email

12
00:00:39,000 --> 00:00:42,000
and password like this

13
00:00:43,000 --> 00:00:45,000
and we could now validate them.

14
00:00:45,000 --> 00:00:47,000
But this is actually not required

15
00:00:47,000 --> 00:00:50,000
since I'll verify these credentials anyways.

16
00:00:50,000 --> 00:00:53,000
I'll look for a user with this email

17
00:00:53,000 --> 00:00:57,000
and I'll then verify whether the stored password for

18
00:00:57,000 --> 00:00:59,000
that user is the one that was entered.

19
00:00:59,000 --> 00:01:03,000
So, we don't need to validate the values submitted

20
00:01:03,000 --> 00:01:07,000
by the user because we'll check whether we find a valid user

21
00:01:07,000 --> 00:01:09,000
for those values anyways.

22
00:01:09,000 --> 00:01:13,000
So, therefore, we'll need to get an existing user by looking

23
00:01:13,000 --> 00:01:15,000
for a user with this email.

24
00:01:17,000 --> 00:01:18,000
Hence, in user.js,

25
00:01:18,000 --> 00:01:22,000
we can export a function called getUserByEmail,

26
00:01:24,000 --> 00:01:28,000
and I expect to get the email as a parameter.

27
00:01:28,000 --> 00:01:32,000
And here, I then wanna return db.prepare,

28
00:01:33,000 --> 00:01:37,000
select all columns from users,

29
00:01:38,000 --> 00:01:40,000
so from the user's table

30
00:01:40,000 --> 00:01:45,000
where the email column has a value of question mark

31
00:01:45,000 --> 00:01:48,000
and the concrete value will be inserted by calling Get

32
00:01:48,000 --> 00:01:50,000
and by passing the email to it.

33
00:01:52,000 --> 00:01:56,000
And this will then return an object with the user data.

34
00:01:56,000 --> 00:01:59,000
So, the id, the email, and the hashed password

35
00:01:59,000 --> 00:02:02,000
if we find one for the provided email.

36
00:02:03,000 --> 00:02:06,000
So, existing user is the result of calling getUserByEmail

37
00:02:08,000 --> 00:02:11,000
and by passing the email to this function.

38
00:02:13,000 --> 00:02:17,000
Now, if we don't have an existing user, if that's undefined,

39
00:02:17,000 --> 00:02:21,000
I know that I didn't find a user for the provided email,

40
00:02:21,000 --> 00:02:25,000
and that of course means that some invalid data was entered.

41
00:02:26,000 --> 00:02:29,000
Now, since we're still on the auth form here,

42
00:02:29,000 --> 00:02:32,000
and since we're still using useFormState,

43
00:02:32,000 --> 00:02:36,000
we can take advantage of the way we output errors.

44
00:02:36,000 --> 00:02:38,000
And if we don't find a user,

45
00:02:38,000 --> 00:02:43,000
we can therefore return an object with an error key just

46
00:02:43,000 --> 00:02:46,000
as we did it in the signup function, for example here,

47
00:02:46,000 --> 00:02:48,000
for an existing email address.

48
00:02:50,000 --> 00:02:53,000
And in that errors key, we can store an object

49
00:02:53,000 --> 00:02:56,000
where I could add a key named email

50
00:02:56,000 --> 00:03:00,000
where we could say, 'Could not authenticate user,

51
00:03:00,000 --> 00:03:04,000
please check your credentials.'

52
00:03:06,000 --> 00:03:09,000
Now, if we make it past this, if check, we know

53
00:03:09,000 --> 00:03:14,000
that we do have a user for the given email address,

54
00:03:14,000 --> 00:03:17,000
but of course the password might be wrong.

55
00:03:17,000 --> 00:03:21,000
But we can verify that password with help of a function

56
00:03:21,000 --> 00:03:24,000
that's part of the hash.js file.

57
00:03:24,000 --> 00:03:27,000
This verifyPassword function,

58
00:03:28,000 --> 00:03:31,000
which will in the end return a boolean depending

59
00:03:31,000 --> 00:03:33,000
on whether the password entered

60
00:03:33,000 --> 00:03:38,000
by the user fits the hash password we have in our database.

61
00:03:38,000 --> 00:03:41,000
Of course, the user does not enter the password

62
00:03:41,000 --> 00:03:45,000
in a hashed form, but we essentially recreate the hash here

63
00:03:45,000 --> 00:03:49,000
and then compare the stored hashed password

64
00:03:49,000 --> 00:03:53,000
to the rehashed supplied password.

65
00:03:54,000 --> 00:03:58,000
So, therefore, in auth-actions we can create a new constant,

66
00:03:58,000 --> 00:04:00,000
which could be called isValidPassword,

67
00:04:01,000 --> 00:04:04,000
which holds the result of calling verifyPassword,

68
00:04:06,000 --> 00:04:10,000
where we pass the existing user password as a first value,

69
00:04:12,000 --> 00:04:15,000
which is the hash password we found in the database

70
00:04:15,000 --> 00:04:17,000
for the existing user,

71
00:04:17,000 --> 00:04:21,000
and then the entered password as a second parameter.

72
00:04:23,000 --> 00:04:28,000
Now, if we don't have a valid password, if this is false,

73
00:04:28,000 --> 00:04:32,000
then I wanna return that same error maybe

74
00:04:32,000 --> 00:04:35,000
for a key name password, though that's up to you.

75
00:04:38,000 --> 00:04:41,000
But if we make it past the safe check, we know

76
00:04:41,000 --> 00:04:45,000
that we found a user or the provided email address

77
00:04:45,000 --> 00:04:49,000
and that the password of this user seems to be correct.

78
00:04:49,000 --> 00:04:51,000
So in that case,

79
00:04:51,000 --> 00:04:56,000
I wanna do what I also did before in the signup step.

80
00:04:56,000 --> 00:04:59,000
I want to create an auth session

81
00:04:59,000 --> 00:05:02,000
and let's say redirect the user.

82
00:05:03,000 --> 00:05:05,000
So, I'll copy this code

83
00:05:05,000 --> 00:05:08,000
and paste it down here at the end

84
00:05:08,000 --> 00:05:10,000
of the login server action.

85
00:05:12,000 --> 00:05:16,000
Now, the ID here is the existingUser.id though,

86
00:05:17,000 --> 00:05:20,000
and with that we're creating a session

87
00:05:20,000 --> 00:05:22,000
if we have a valid user.

88
00:05:22,000 --> 00:05:24,000
Otherwise, we don't.

89
00:05:24,000 --> 00:05:25,000
Now, we just need to make sure

90
00:05:25,000 --> 00:05:30,000
that this login server action is actually getting used

91
00:05:30,000 --> 00:05:32,000
in that AuthForm component.

