WEBVTT

00:00.320 --> 00:09.770
So after all this hard work implementing the Remember Token model, we finally got it ready and we've

00:09.770 --> 00:11.150
got more work.

00:11.180 --> 00:21.710
So the next step is to mix the working with database storing fetching this database stored token and

00:21.710 --> 00:22.460
cookies.

00:22.460 --> 00:31.400
That's why I highlight on this step of the diagram, as we need to store the token in a cookie.

00:31.400 --> 00:38.510
And as usual, when we have those mix responsibilities, when something needs to work with both the

00:38.510 --> 00:47.900
database and maybe with cookies and potentially other parts of the system, that's the use case for

00:47.930 --> 00:49.370
a service class.

00:50.210 --> 00:53.660
Let's just call it Remember Me.

00:54.140 --> 01:00.720
I am not sure if there is a more obvious name of what it can do.

01:01.200 --> 01:07.710
It just handles everything related to remembering a person.

01:09.720 --> 01:12.810
That's just a class that doesn't inherit anything.

01:12.840 --> 01:18.630
And now let's go and implement every single feature does that.

01:18.630 --> 01:20.400
This needs to have.

01:21.570 --> 01:27.120
Let's begin by adding a setting that will be a constant.

01:27.120 --> 01:30.990
And that's just cookie name.

01:31.200 --> 01:33.360
Let's call it remember token.

01:33.450 --> 01:40.440
It's easier to find a constant in a class than just to figure out that there is some magic string somewhere

01:40.440 --> 01:41.820
inside the code.

01:42.210 --> 01:45.600
Next up would be the token lifetime.

01:45.630 --> 01:46.200
Hmm.

01:46.320 --> 01:52.140
It seems we already have this someplace, don't we?

01:52.170 --> 01:55.890
It's like the same, like the remember token.

01:55.920 --> 01:57.570
Okay, that's the same one.

01:57.780 --> 02:00.810
Why won't we make this token public?

02:01.680 --> 02:04.140
I don't see anything wrong with that.

02:05.610 --> 02:08.220
This means we don't really have to define it.

02:08.250 --> 02:12.570
We're just going to use the constant from the Remember token class.

02:13.050 --> 02:17.820
And now let's start adding some logic here.

02:17.850 --> 02:24.030
Let's begin with the create token one for the specific user ID.

02:24.420 --> 02:27.930
Keep in mind I am typing those variables.

02:27.960 --> 02:31.260
Later on we're going to see if this works fine or not.

02:32.640 --> 02:33.300
Okay.

02:33.300 --> 02:37.440
Um should this return a token?

02:39.180 --> 02:40.170
Why not?

02:40.200 --> 02:47.040
Okay, so what we need to do here is we should create a token.

02:48.480 --> 02:54.780
We've got the Remember Token class which has this handy create for user method to which we pass the

02:54.780 --> 02:55.440
user ID.

02:56.230 --> 03:05.860
And this is how easy we have it to create a token and store it inside the database with everything properly

03:05.860 --> 03:06.760
set up.

03:07.000 --> 03:13.060
And the next step is to set a cookie.

03:13.270 --> 03:15.430
So we're going to create a method for that.

03:15.430 --> 03:19.000
And the cookie only needs the actual token string.

03:19.420 --> 03:24.820
That's why we can get the token field from this generated token.

03:24.850 --> 03:26.530
Now this does not exist.

03:26.530 --> 03:29.620
So we need to add this method.

03:30.490 --> 03:34.630
Finally let's return a token.

03:36.220 --> 03:39.760
So let's go ahead with this one shall we.

03:40.510 --> 03:45.280
That's public or I'm not sure if this should be public.

03:45.310 --> 03:45.670
Mm.

03:46.150 --> 03:47.440
No definitely not.

03:47.440 --> 03:52.990
This should be private static function set cookie.

03:53.440 --> 03:59.570
It only needs the token and I think it shouldn't really return anything.

04:02.150 --> 04:05.540
Okay, so when does it expire?

04:05.570 --> 04:13.010
Let's calculate that by adding time to remember token.

04:14.330 --> 04:15.170
Token.

04:15.170 --> 04:16.220
Lifetime.

04:17.150 --> 04:22.130
That's our constant which has everything nicely calculated in seconds.

04:23.480 --> 04:26.840
And now we just need to call set cookie.

04:27.920 --> 04:30.170
The name is static.

04:30.890 --> 04:31.190
Cookie.

04:31.190 --> 04:31.910
Name.

04:33.020 --> 04:35.720
The value is the token.

04:36.140 --> 04:37.310
The expiry date.

04:37.310 --> 04:41.330
We have it calculated the path.

04:41.660 --> 04:46.460
Well, that's the root path domain.

04:46.880 --> 04:48.380
Let's leave it empty.

04:48.860 --> 04:50.840
Should it be a secure cookie?

04:50.870 --> 04:51.320
Yes.

04:51.320 --> 04:58.790
So that's the reason we need a secure cookie for it and it is an HTTP only cookie.

05:01.040 --> 05:03.530
I think we've got the wrong argument name.

05:05.480 --> 05:10.040
Okay, so let me explain this part why this is an HTTP only cookie.

05:10.070 --> 05:16.040
So the HTTP only cookie means it can only be accessed on the server.

05:16.040 --> 05:19.700
So the browser sends this cookie with every request.

05:19.790 --> 05:28.610
I can access it on the server using PHP or whatever backend language is, but this cookie cannot be

05:28.610 --> 05:33.050
accessed through the browser client using JavaScript.

05:33.170 --> 05:42.050
And this just protects us from any malicious users from cross-site scripting, when there might be some

05:42.050 --> 05:50.930
malicious JavaScript injected to your website that might want to read this cookie and send it over to

05:50.960 --> 05:52.100
some other user.

05:52.100 --> 05:57.360
So we really need to protect ourselves from this kind of attack.

05:57.360 --> 06:01.050
So as a reminder, the shortcut is XSS.

06:01.080 --> 06:05.220
It is a shortcut for cross-site scripting.

06:05.220 --> 06:06.750
And we don't want that.

06:06.750 --> 06:12.780
That's why we need to protect ourselves by setting an HTTP only cookie.

06:15.300 --> 06:19.860
Now there's gonna be time when we'd like to remove a cookie.

06:19.890 --> 06:25.770
If someone logs out, then we should certainly remove the Remember Me cookie.

06:26.400 --> 06:32.070
Let's also add this static method then, which would be void.

06:32.130 --> 06:39.480
And to remove a cookie, just call set cookie using the same cookie name.

06:40.650 --> 06:43.650
The value is empty because we use the same method.

06:43.650 --> 06:47.160
And the trick is to set time in the past.

06:47.940 --> 06:51.690
That's why I get the current time -one hour.

06:51.850 --> 06:57.670
this is just one hour in seconds, but I need to use exactly the same parameters.

06:57.670 --> 07:03.040
So I repeat everything and this removes a cookie.

07:05.950 --> 07:09.100
Next up we need to rotate the token.

07:09.100 --> 07:11.230
So I've explained that earlier.

07:11.230 --> 07:17.530
Every time we use a token we should regenerate it.

07:17.530 --> 07:23.830
And this actually accepts a token instance which needs to be fetched earlier.

07:24.520 --> 07:25.750
It's void.

07:25.750 --> 07:30.610
And the way it works is we rotate the token.

07:34.690 --> 07:37.270
Or I think it only has the rotate method.

07:37.300 --> 07:37.870
Yeah.

07:38.080 --> 07:38.590
Okay.

07:38.620 --> 07:42.340
So this will regenerate the actual token the expiry date.

07:42.340 --> 07:44.350
And it will save the changes.

07:44.350 --> 07:51.220
That's why I don't really need to get a result from it because it will be inside this object the token.

07:51.730 --> 08:03.520
And now I can call set cookie passing the new token, which will also automatically recalculate the

08:03.520 --> 08:06.700
new expiry date, which is 30 days from now.

08:06.730 --> 08:12.820
Because we are using the same constant from remember token method.

08:14.380 --> 08:21.970
So we still would have to remove the token from the cookie and from the database when someone logs out.

08:21.970 --> 08:24.520
But why won't we leave that for later?

08:24.700 --> 08:30.640
For now, let's just add the functionality of storing this token.

08:31.180 --> 08:35.830
That's why I'm going to add a public method called Validate Token.

08:36.670 --> 08:41.080
It returns an instance of user or null.

08:41.260 --> 08:51.350
What this means is it's a method that should return the user model of the user that was remembered.

08:51.470 --> 08:59.630
Or if we can't find any token in the in the cookie or in the database that is not expired or doesn't

08:59.630 --> 09:05.420
match the given value stored in the cookie, then we just return null.

09:05.420 --> 09:13.340
It means there is just no user that was remembered under a specific token that is stored in a cookie.

09:15.230 --> 09:26.090
This means we need to get the token string which is stored in a cookie, and we use the cookie name,

09:27.140 --> 09:28.880
whether it be static here.

09:29.600 --> 09:33.560
If this is not found, that's null.

09:34.190 --> 09:40.220
So if the token string is falsy, we return null.

09:40.220 --> 09:47.150
This means well, we can't find the token in the cookie, so nothing to do more.

09:47.180 --> 09:49.970
The next step is to try to get the token.

09:50.330 --> 10:00.290
So we've got the remember token class find valid to which we pass the token string.

10:00.320 --> 10:06.680
The job of this we created it previously was to find a Non-expired token.

10:08.840 --> 10:17.570
If we can't find the token again we return null.

10:20.030 --> 10:21.650
Okay, so what next?

10:21.890 --> 10:26.360
If there is a token in the database that is not expired?

10:27.230 --> 10:31.610
Let's use the user model find and just find the user by id.

10:31.940 --> 10:33.710
So where do we get the user id?

10:33.770 --> 10:37.250
Well it is in the token.

10:39.440 --> 10:50.970
So if we have found the user what we need to do is we need to rotate the token.

10:51.210 --> 10:55.800
So we need to generate a new one because the previous one was already used.

10:55.800 --> 10:59.760
So for the security reasons we replace it.

10:59.760 --> 11:02.250
So I've explained that a couple of times.

11:03.300 --> 11:09.840
And then we return the result of user doesn't matter if the user was found or not.

11:10.440 --> 11:14.070
So the find should return static or null.

11:14.100 --> 11:15.990
Let's also fix this type.

11:16.020 --> 11:18.900
That's just a base method from the model.

11:19.710 --> 11:22.980
And this is our logic for validating the token.

11:22.980 --> 11:29.040
So a quick reminder that this cookie super global contains cookies of the current user.

11:29.820 --> 11:32.580
That's why we don't need any parameters in here.

11:32.580 --> 11:38.550
It essentially means please give me the user that was remembered.

11:38.550 --> 11:43.320
And we have stored his data both in the cookie and in the database.

11:44.340 --> 11:48.670
Returning null means that we can't find such user.

11:51.040 --> 11:58.150
So to finish off with this class and have the Remember Me functionality almost complete so that we can

11:58.150 --> 12:05.410
connect it with the authentication class, we need another method to clear both the cookie and the database

12:05.410 --> 12:09.520
token, which will be used when someone signs out.

12:09.520 --> 12:11.860
We need to clear all the traces.

12:11.890 --> 12:13.990
We can't seem to spell that right.

12:13.990 --> 12:18.820
So this is a function called clear token.

12:18.850 --> 12:26.830
Again we don't require any parameters because we assume those are the cookies of the current user.

12:26.830 --> 12:30.070
So first we need the token string.

12:30.070 --> 12:32.560
We use the super global cookie.

12:33.670 --> 12:36.340
We get the cookie name.

12:38.590 --> 12:42.460
Which we can either find it or there is null.

12:42.460 --> 12:43.480
So.

12:45.130 --> 12:55.480
If the token string was found, then we try to fetch the token from the database.

12:55.480 --> 13:02.830
So we do remember token find valid and we pass the token string.

13:04.690 --> 13:10.150
If we have found the token and it's still valid.

13:11.320 --> 13:13.270
There is another method we can call.

13:13.690 --> 13:16.930
Call delete doesn't exist.

13:16.960 --> 13:18.190
We're going to create it soon.

13:18.190 --> 13:20.140
That's also a very useful one.

13:20.170 --> 13:25.270
And regardless we make sure we remove the cookie.

13:26.560 --> 13:26.890
Okay.

13:26.890 --> 13:30.850
So the token doesn't have a delete method.

13:30.850 --> 13:35.590
But I think it's something that would be super useful for all models.

13:36.610 --> 13:38.680
Same as the save method.

13:38.710 --> 13:42.550
This would just mean delete this current record.

13:42.890 --> 13:48.380
So let me add public function not static called delete.

13:49.610 --> 13:53.600
And it's just going to get the database using app.

13:53.630 --> 13:56.300
Get database.

13:59.900 --> 14:07.070
And first we need to make sure that this current object has an ID assigned.

14:07.100 --> 14:17.570
That's why we check for the is set or just alternatively if it is not set we just return immediately.

14:18.680 --> 14:24.500
And that way we can only get the database instance if there is anything to delete.

14:25.490 --> 14:27.380
Let's also make it void.

14:29.120 --> 14:36.440
And now if we have an ID on this object then we can try and attempt deleting it.

14:36.470 --> 14:38.330
Let's write an SQL.

14:38.840 --> 14:43.410
So we have written the delete statement previously in the fixtures.

14:43.440 --> 14:45.030
Not sure if you remember that.

14:45.720 --> 14:48.840
So the syntax is delete from.

14:49.740 --> 14:53.880
This needs to be connected with the table name.

14:54.300 --> 14:58.800
And we add a where clause that is very important.

14:58.800 --> 15:03.780
So that we point to a specific ID and we use a prepared statement.

15:04.230 --> 15:15.480
So then we can run DB query passing the SQL and getting the current ID, which we assume at this point

15:15.480 --> 15:18.900
is assigned because we have verified that first.

15:19.920 --> 15:20.640
That's it.

15:20.640 --> 15:22.110
This is the delete method.

15:22.110 --> 15:29.010
We can now jump back to Remember Me functionality, which should work fine at this point.

15:29.220 --> 15:34.230
Okay, so we really did a lot in a limbo.

15:34.260 --> 15:35.910
Let me call it this way.

15:35.910 --> 15:43.980
We haven't been able to verify anything because well, as I've said, this process of getting the token

15:44.010 --> 15:53.790
isn't really that simple, but I think we really learned a lot, and that's really a useful exercise

15:53.790 --> 15:54.060
to see.

15:54.060 --> 16:03.690
How can you mix logic that works with database, and then with cookies or sessions or any other storage

16:03.690 --> 16:05.400
mechanism for that matter?

16:05.640 --> 16:15.210
So our final step is to just connect this Remember Me class, which basically is encapsulating all the

16:15.210 --> 16:19.080
logic related to managing the Remember Me feature.

16:19.500 --> 16:22.830
So we're going to add a checkbox here to this form.

16:23.460 --> 16:28.470
And every single time it's going to be checked we're going to create this token.

16:28.470 --> 16:33.030
So next up we're going to be connecting the dots with the auth service.

16:33.030 --> 16:34.350
So let's have it open.

16:35.790 --> 16:38.160
And we're going to be testing this feature.

16:38.250 --> 16:39.660
Let's have a break now.
