How to reliably detect an expired Laravel session?

556 Views Asked by At

I am working on a web client which does a lot of AJAX request. The backend is written in Laravel. If the backend throws a PHP exception, the backend sends a JSON response to the client whose header shows a HTTP error code and whose body includes the name of the PHP exception.

If a user has been inactive for a while, the HTTP session expires. This means that the session ID transmitted by the client has been discarded by the backend and thus the session ID is unknown. I would have excepted Laravel to throw a proper PHP exception in this case, e.g. something like SessionIdUnknown, SessionExpired or anything of that sort. This would enable the web client to reliably detect this situation and react accordingly.

However, it seems as if Laravel's session management does not care at all, whether the session exists or not. The request will potentially fail later (with some unforeseeable error), if some code further down the call graph tries to load a value from the session and fails, because the value is unset or null.

Step debugging unveiled the following trace:

1. Illuminate\Session\Middleware\StartSession::handle
2.   Illuminate\Session\Middleware\StartSession::getSession
3.     Illuminate\Session\Store::setId
4.   Illuminate\Session\Middleware\StartSession::handleStatefulRequest
5.     Illuminate\Session\Middleware\StartSession::startSession
6.       Illuminate\Session\Store::start
7.         Illuminate\Session\Store::loadSession
8.           Illuminate\Session\Store::readFromHandler
  • In step 2, the middleware reads the claimed session ID from the request (e.g. from the cookie sent by the client).
  • In step 3, the middleware sets the ID on the Store object for later use, but that is really only a simply setter; nothing else happens here.
  • In step 8 the "real" magic happens, the Store object tries to load the the persisted session data with respect to the previously set ID.

However, the code looks like that

protected function readFromHandler() {
  if ($data = $this->handler->read($this->getId())) {
    $data = @unserialize($this->prepareForUnserialize($data));

    if ($data !== false && ! is_null($data) && is_array($data)) {
      return $data;
    }
  }

  return [];
}

Any error by unserialize is suppressed via @-operator. If anything goes wrong, i.e. unserialized has returned false, null or anything which is not an array, the method silently returns the empty array []. So we cannot distinguish, if the session did not exist (error case) or if the session is simply empty because no data has previously been stored (no error).

Please tell me that I am erring! How do I reliably detect an non-existing or expired session in the backend and return a consistent error message?

I would have expected the following behavior by Laravel:

  • If the client does not sent a session ID via a cookie, then create a new session and return the newly created session ID back to client with set-cookie.
  • If the client sends a session ID via a cookie and the session ID exist, then proceed.
  • If the client sends a session ID via a cookie and the session ID does not exist or cannot be loaded, stop further processing of the request and return an error response.
0

There are 0 best solutions below