So, let's in a log in server action.
For that I'll go to auth-actions.js.
And here at the bottom of the file, for example,
I'll export a new async function called login.
And here, I also expect to get a previous state
since this server action function
will also be set as a value for use form state.
And I'll expect to get the formData,
so exactly the same parameters
as we get on the signup server action.
Therefore, we can of course also retrieve email
and password like this
and we could now validate them.
But this is actually not required
since I'll verify these credentials anyways.
I'll look for a user with this email
and I'll then verify whether the stored password for
that user is the one that was entered.
So, we don't need to validate the values submitted
by the user because we'll check whether we find a valid user
for those values anyways.
So, therefore, we'll need to get an existing user by looking
for a user with this email.
Hence, in user.js,
we can export a function called getUserByEmail,
and I expect to get the email as a parameter.
And here, I then wanna return db.prepare,
select all columns from users,
so from the user's table
where the email column has a value of question mark
and the concrete value will be inserted by calling Get
and by passing the email to it.
And this will then return an object with the user data.
So, the id, the email, and the hashed password
if we find one for the provided email.
So, existing user is the result of calling getUserByEmail
and by passing the email to this function.
Now, if we don't have an existing user, if that's undefined,
I know that I didn't find a user for the provided email,
and that of course means that some invalid data was entered.
Now, since we're still on the auth form here,
and since we're still using useFormState,
we can take advantage of the way we output errors.
And if we don't find a user,
we can therefore return an object with an error key just
as we did it in the signup function, for example here,
for an existing email address.
And in that errors key, we can store an object
where I could add a key named email
where we could say, 'Could not authenticate user,
please check your credentials.'
Now, if we make it past this, if check, we know
that we do have a user for the given email address,
but of course the password might be wrong.
But we can verify that password with help of a function
that's part of the hash.js file.
This verifyPassword function,
which will in the end return a boolean depending
on whether the password entered
by the user fits the hash password we have in our database.
Of course, the user does not enter the password
in a hashed form, but we essentially recreate the hash here
and then compare the stored hashed password
to the rehashed supplied password.
So, therefore, in auth-actions we can create a new constant,
which could be called isValidPassword,
which holds the result of calling verifyPassword,
where we pass the existing user password as a first value,
which is the hash password we found in the database
for the existing user,
and then the entered password as a second parameter.
Now, if we don't have a valid password, if this is false,
then I wanna return that same error maybe
for a key name password, though that's up to you.
But if we make it past the safe check, we know
that we found a user or the provided email address
and that the password of this user seems to be correct.
So in that case,
I wanna do what I also did before in the signup step.
I want to create an auth session
and let's say redirect the user.
So, I'll copy this code
and paste it down here at the end
of the login server action.
Now, the ID here is the existingUser.id though,
and with that we're creating a session
if we have a valid user.
Otherwise, we don't.
Now, we just need to make sure
that this login server action is actually getting used
in that AuthForm component.