Transcript
-
Next, let's go ahead and take care of our login form. So if we dive back into our text editor here, when we're registering a user, we're able to log them in because we already have access to that brand new user
-
record that we have created. Whenever it comes to logging in a user, however, all that we have is the email and the password that the user has sent up with the login form.
-
So then what we need to be able to do is take that email and the password, find the applicable user for it, and then log them in the same way that we are with registration. So step one here is to get the user record.
-
And for this, the AuthFinder mixin that we have on our user model is going to come into play again. So if we dive back into our browser real quick and take a look at this with AuthFinder mixin once more,
-
we have the class being defined right here. So inside of this class, there's our hash password before save hook. If we scroll down a little bit,
-
we'll see the method used to actually find the authenticated user via query. And if we scroll down a little bit further, we're going to see a method called verify credentials.
-
And this method does exactly as the name suggests. It's going to take in the user's unique ID, in our case, that's the email, as well as their password.
-
And it's going to make sure that we have a value for both, throwing an error if we don't. It will use that find for auth method to find just above this method to actually query for the user based off of the UID provided in.
-
With whatever that returns back, it's going to check and make sure that it did actually return a user. If it did not, it's going to just hash the password, and we'll cover what that's for here in a second as well.
-
And then throw an error for invalid user credentials. However, if it did find a user, we'll continue onward. It will grab the actual hashed password user value from the user that it found
-
with the find for auth method. And if the found user does not have a value for the password, it will throw an error there as well. Lastly, if all went good, then it will actually hash the password and
-
verify that the user's stored hash within the database matches what they have provided. If it did, then it will return back that user.
-
Otherwise, it will throw that invalid user credentials error. So in essence, we can provide this verify credentials method, our user's unique identifier, which is their email in our case,
-
as well as their password. And if it successfully found a user that matches the password provided for the email provided, it will return that user back to us,
-
which we can then use to log the user in, in the same fashion that we're doing with our registration step. Before we move onward with that, though, let's take a second to explain what
-
this particular hash is doing right here within the verify credentials method. And this is explained with an example here within the documentation. If we take a look at basic authentication without that step in play, and
-
the user provides in an email that we don't actually have within our database, and we just immediately abort out, there will be a slight timing difference
-
between a failed attempt and a successful attempt due to that small amount of time that verifying the hash will actually take. And they explain as well that that is a timing attack.
-
And they link out to the Wikipedia page there, if you should be interested, describing in more detail what that is. So in essence, if we dive back into the withAuthFinderVerifyCredentials method,
-
this extra hash is here to ensure that a failed attempt to log in takes the same amount of time as a successful attempt to log in, so
-
that they're both actually hashing something. And there isn't that time difference between the two, because if there was a time difference, if somebody was attempting to find valid emails within your system,
-
they would be able to discern that based off of that difference in time. So with all of that covered, let's close these out, and let's take care of our login.
-
So let's hide our browser back away, and let's jump back into our login controller. Let's get rid of our console log, and we're gonna have an extra step,
-
which will serve as our step two, where we'll need to verify the user's credentials, which means this becomes our step three, and lastly, that our step four.
-
So to verify our user credentials, as we saw just a moment ago, we can use that verifyCredentials method on our user model that's being added in from the withAuthFinderMixer.
-
So we do const user, because we'll get back a user if this succeeds, await, import our user model, dot, and call that verifyCredentials method.
-
We'll need to pass in our UID and our password, which we can extract out of our validated data from our request body. So for this, we have our email and our password.
-
Our email is our user's unique identifier, so we'll pass it in as the UID value. And then our password is the password. So if this succeeds, we'll get back our user.
-
And if it does not, it will throw an invalid credentials error. So it will automatically stop execution of this code for us. So we don't need to actually handle that if we don't want to customize that error in any way.
-
If you do wanna customize that error, just wrap this section here in a try/catch block and send out whatever your custom error is that you wanna send. Okay, so now that we have our user, we just need to treat this relatively similar
-
from here on out as our registration step. So we just grab auth out of our HTTP context, just like so. And then we'll await auth, use the web guard, and
-
log in that user that we got back from our verifyCredentials step. And with those two additional lines, we have now verified that the user has provided a valid password for the email that they're providing as well.
-
We've gotten back that user's record, and we have logged them in successfully. So at this point, if we dive back into our browser, and let's give this a run. So if I'm remembering correctly, we registered test@test.com and
-
some value there for the password. Let's run that, and there we go. So now we are logged in as John Doe, as noted by our navigation up here. We can click on this to log back out.
-
Let's dive back into our login page, and let's try test@test.com with some non-accurate password there. Log in, and we're gonna get redirected right back here.
-
Our email will populate due to that old value that we're populating from our session data. Again, password's omitted there for security reasons. So now what we wanna do is show that an error actually occurred here.
-
So let's hide our browser back away. Let's scroll on down to our resources, views, pages, off, and jump into our login page here. Down at the bottom, underneath everything here,
-
let's go ahead and inspect all of our flash messages. So we can do flash_messages.all to see exactly what it is that we're getting back whenever we actually fail a login attempt.
-
So let's jump back into our browser, test@test.com, some invalid password there, log in, and there we go.
-
So we see within our errors bag here an invalid credentials error. We can give this key a copy. Let's jump back into our text editor, and
-
we can make use of the error.hjs component helper. So @error, provide the key of the error in that we wanna check for, and
-
this will serve relatively similar to an if statement. So if this error component here can find an error specifically for the key that we're providing in,
-
then it will render out whatever we put inside as child content. Otherwise, it won't render that child content out.
-
So we can do p class text-read 500 bg-read 50 d3-rounded text-extra small to give ourselves a little alert-based thing here.
-
And let's actually give that a role alert as well. And then this error component will actually inject the error directly into the child content and make it accessible via $message.
-
So whatever the value is for that key, we jump back into our browser. Right here, we'll get injected inside of that error component as that $message value, so let's hide that back away and give this a save.
-
We can go ahead and scroll back down and get rid of our inspect call, give that a save once more, jump back into our browser, and let's try that out again.
-
So let's do test@test.com and some invalid password there, log in, and there we go. So now we see our error invalid user credentials.
Logging In An Existing User
We'll learn how we can login an existing user using just their email and password. We'll discuss how the AuthFinder mixin protects us from timing attacks, and how we can use it to verify the accuracy of a user's password.

- Created by
- @tomgobich
- Published
Join the Discussion 0 comments
Be the first to comment!