So after all this hard work implementing the Remember Token model, we finally got it ready and we've
got more work.
So the next step is to mix the working with database storing fetching this database stored token and
cookies.
That's why I highlight on this step of the diagram, as we need to store the token in a cookie.
And as usual, when we have those mix responsibilities, when something needs to work with both the
database and maybe with cookies and potentially other parts of the system, that's the use case for
a service class.
Let's just call it Remember Me.
I am not sure if there is a more obvious name of what it can do.
It just handles everything related to remembering a person.
That's just a class that doesn't inherit anything.
And now let's go and implement every single feature does that.
This needs to have.
Let's begin by adding a setting that will be a constant.
And that's just cookie name.
Let's call it remember token.
It's easier to find a constant in a class than just to figure out that there is some magic string somewhere
inside the code.
Next up would be the token lifetime.
Hmm.
It seems we already have this someplace, don't we?
It's like the same, like the remember token.
Okay, that's the same one.
Why won't we make this token public?
I don't see anything wrong with that.
This means we don't really have to define it.
We're just going to use the constant from the Remember token class.
And now let's start adding some logic here.
Let's begin with the create token one for the specific user ID.
Keep in mind I am typing those variables.
Later on we're going to see if this works fine or not.
Okay.
Um should this return a token?
Why not?
Okay, so what we need to do here is we should create a token.
We've got the Remember Token class which has this handy create for user method to which we pass the
user ID.
And this is how easy we have it to create a token and store it inside the database with everything properly
set up.
And the next step is to set a cookie.
So we're going to create a method for that.
And the cookie only needs the actual token string.
That's why we can get the token field from this generated token.
Now this does not exist.
So we need to add this method.
Finally let's return a token.
So let's go ahead with this one shall we.
That's public or I'm not sure if this should be public.
Mm.
No definitely not.
This should be private static function set cookie.
It only needs the token and I think it shouldn't really return anything.
Okay, so when does it expire?
Let's calculate that by adding time to remember token.
Token.
Lifetime.
That's our constant which has everything nicely calculated in seconds.
And now we just need to call set cookie.
The name is static.
Cookie.
Name.
The value is the token.
The expiry date.
We have it calculated the path.
Well, that's the root path domain.
Let's leave it empty.
Should it be a secure cookie?
Yes.
So that's the reason we need a secure cookie for it and it is an HTTP only cookie.
I think we've got the wrong argument name.
Okay, so let me explain this part why this is an HTTP only cookie.
So the HTTP only cookie means it can only be accessed on the server.
So the browser sends this cookie with every request.
I can access it on the server using PHP or whatever backend language is, but this cookie cannot be
accessed through the browser client using JavaScript.
And this just protects us from any malicious users from cross-site scripting, when there might be some
malicious JavaScript injected to your website that might want to read this cookie and send it over to
some other user.
So we really need to protect ourselves from this kind of attack.
So as a reminder, the shortcut is XSS.
It is a shortcut for cross-site scripting.
And we don't want that.
That's why we need to protect ourselves by setting an HTTP only cookie.
Now there's gonna be time when we'd like to remove a cookie.
If someone logs out, then we should certainly remove the Remember Me cookie.
Let's also add this static method then, which would be void.
And to remove a cookie, just call set cookie using the same cookie name.
The value is empty because we use the same method.
And the trick is to set time in the past.
That's why I get the current time -one hour.
this is just one hour in seconds, but I need to use exactly the same parameters.
So I repeat everything and this removes a cookie.
Next up we need to rotate the token.
So I've explained that earlier.
Every time we use a token we should regenerate it.
And this actually accepts a token instance which needs to be fetched earlier.
It's void.
And the way it works is we rotate the token.
Or I think it only has the rotate method.
Yeah.
Okay.
So this will regenerate the actual token the expiry date.
And it will save the changes.
That's why I don't really need to get a result from it because it will be inside this object the token.
And now I can call set cookie passing the new token, which will also automatically recalculate the
new expiry date, which is 30 days from now.
Because we are using the same constant from remember token method.
So we still would have to remove the token from the cookie and from the database when someone logs out.
But why won't we leave that for later?
For now, let's just add the functionality of storing this token.
That's why I'm going to add a public method called Validate Token.
It returns an instance of user or null.
What this means is it's a method that should return the user model of the user that was remembered.
Or if we can't find any token in the in the cookie or in the database that is not expired or doesn't
match the given value stored in the cookie, then we just return null.
It means there is just no user that was remembered under a specific token that is stored in a cookie.
This means we need to get the token string which is stored in a cookie, and we use the cookie name,
whether it be static here.
If this is not found, that's null.
So if the token string is falsy, we return null.
This means well, we can't find the token in the cookie, so nothing to do more.
The next step is to try to get the token.
So we've got the remember token class find valid to which we pass the token string.
The job of this we created it previously was to find a Non-expired token.
If we can't find the token again we return null.
Okay, so what next?
If there is a token in the database that is not expired?
Let's use the user model find and just find the user by id.
So where do we get the user id?
Well it is in the token.
So if we have found the user what we need to do is we need to rotate the token.
So we need to generate a new one because the previous one was already used.
So for the security reasons we replace it.
So I've explained that a couple of times.
And then we return the result of user doesn't matter if the user was found or not.
So the find should return static or null.
Let's also fix this type.
That's just a base method from the model.
And this is our logic for validating the token.
So a quick reminder that this cookie super global contains cookies of the current user.
That's why we don't need any parameters in here.
It essentially means please give me the user that was remembered.
And we have stored his data both in the cookie and in the database.
Returning null means that we can't find such user.
So to finish off with this class and have the Remember Me functionality almost complete so that we can
connect it with the authentication class, we need another method to clear both the cookie and the database
token, which will be used when someone signs out.
We need to clear all the traces.
We can't seem to spell that right.
So this is a function called clear token.
Again we don't require any parameters because we assume those are the cookies of the current user.
So first we need the token string.
We use the super global cookie.
We get the cookie name.
Which we can either find it or there is null.
So.
If the token string was found, then we try to fetch the token from the database.
So we do remember token find valid and we pass the token string.
If we have found the token and it's still valid.
There is another method we can call.
Call delete doesn't exist.
We're going to create it soon.
That's also a very useful one.
And regardless we make sure we remove the cookie.
Okay.
So the token doesn't have a delete method.
But I think it's something that would be super useful for all models.
Same as the save method.
This would just mean delete this current record.
So let me add public function not static called delete.
And it's just going to get the database using app.
Get database.
And first we need to make sure that this current object has an ID assigned.
That's why we check for the is set or just alternatively if it is not set we just return immediately.
And that way we can only get the database instance if there is anything to delete.
Let's also make it void.
And now if we have an ID on this object then we can try and attempt deleting it.
Let's write an SQL.
So we have written the delete statement previously in the fixtures.
Not sure if you remember that.
So the syntax is delete from.
This needs to be connected with the table name.
And we add a where clause that is very important.
So that we point to a specific ID and we use a prepared statement.
So then we can run DB query passing the SQL and getting the current ID, which we assume at this point
is assigned because we have verified that first.
That's it.
This is the delete method.
We can now jump back to Remember Me functionality, which should work fine at this point.
Okay, so we really did a lot in a limbo.
Let me call it this way.
We haven't been able to verify anything because well, as I've said, this process of getting the token
isn't really that simple, but I think we really learned a lot, and that's really a useful exercise
to see.
How can you mix logic that works with database, and then with cookies or sessions or any other storage
mechanism for that matter?
So our final step is to just connect this Remember Me class, which basically is encapsulating all the
logic related to managing the Remember Me feature.
So we're going to add a checkbox here to this form.
And every single time it's going to be checked we're going to create this token.
So next up we're going to be connecting the dots with the auth service.
So let's have it open.
And we're going to be testing this feature.
Let's have a break now.