Laravel: custom cookie expiration time

The Laravel framework makes a PHP programmers task easier by implementing a lot of features which are pretty much used in every web application. One of those features is authentication, which works like a charm. A part of this feature is remembering a successful authenticated user by setting a cookie.

Let’s start with Laravel’s documentation about this feature:

If you would like to provide “remember me” functionality in your application, you may pass true as the second argument to the attempt method, which will keep the user authenticated indefinitely (or until they manually log out).

So you have 2 options:

  1. “Do not remember”: authentication only lasts the life span of the session itself
  2. “Do remember”: remember a user forever or until they log out

I would like to add another option to it:

  1. “Do remember, but for a specific amount of time”: remember a user for a specific amount of time. For example: 1 day, 1 week, 1 month or 1 year

After a bit of searching and testing I came up with the following solution.

In the controller which attempts to authenticate the user, you probably have something like this:

$loginData = array(
    'email' => Input::get('email'),
    'password' => Input::get('password'),
    'active' => 1
);

if (Auth::attempt($loginData, true)) {
    return Redirect::intended('/');
}

For the app I’m developing I want the user to have the option to choose the duration of the period the user remains logged in. I added a select element to the login form and after a successful authentication we need to code the custom cookie expiration:

$cookieExpiration = intval(Input::get('remember_me_for'));

Laravel sets the authentication cookie in the response. The response is set when the request cycle is finished. At this moment in the code, the cookie hasn’t been set yet so we can’t edit the cookie here. Therefor we set the cookie expiration value in the session:

Session::put('cookie_expiration', $cookieExpiration);

You probably want to validate the value of the cookie expiration, you can use Laravel’s validation class with rules like integer, min and max.

Then head to filters.php and the App::after section. In this section, the cookie is set, so this is the moment to edit it. In the App:after function we should check if the cookie_expiration value is set, if the user is successfully authenticated and if the cookie is available:

App::after(function($request, $response) {
    $cookieName = Auth::getRecallerName();
    if (Session::has('cookie_expiration') && Auth::check() && isset($_COOKIE[$cookieName])) {       
        ...
    }
});

The following step is to edit the cookie and send the response with the edited cookie:

// get the (current/new) cookie values
$cookieValue = Cookie::get($cookieName);
$expiration = Session::get('cookie_expiration');
        
// forget the session var
Session::forget('cookie_expiration');

// change the expiration time
$cookie = Cookie::make($cookieName, $cookieValue, $expiration);
return $response->withCookie($cookie);

That’s it. The “remember me” cookie is changed with the new expiration time and it changes it only once. You are also able to let the user change it again by setting the cookie_expiration value in the session.

The final App:after function looks like this:

App::after(function($request, $response) {
    $cookieName = Auth::getRecallerName();
    if (Session::has('cookie_expiration') && Auth::check() && isset($_COOKIE[$cookieName])) {       
        // get the (current/new) cookie values
        $cookieValue = Cookie::get($cookieName);
        $expiration = Session::get('cookie_expiration');
        
        // forget the session var
        Session::forget('cookie_expiration');

        // change the expiration time
        $cookie = Cookie::make($cookieName, $cookieValue, $expiration);
        return $response->withCookie($cookie);
    }
});

To view the cookies set by the current web page I suggest the “Edit This Cookie” extension for Chrome.

Leave a Reply

Your email address will not be published. Required fields are marked *