Make LazySession startable?

I’m reviewing some hacks that went into our codebase when we adopted zend-expressive-session. They both involve the need to access the session ID from a handler, before the SessionMiddleware has persisted the session and added the cookie to the response.

We have two use cases:

  1. We need the session ID to generate a CSRF token. Our sessions are lockless, so the token is stored separately from the session. When a user first hits the login page, no session exists.
  2. On login we check whether any other session is using the same credentials and regenerate the session. To do this we need to store the regenerated ID against the user record. But it isn’t available until SessionMiddleware handles the reponse.

The hack we have in place involves:

  1. Injecting the SessionPersistenceInterface into our login handler.
  2. Performing a merry dance with the cookies returned in the response from persistSession(), passing them through to initializeSessionFromRequest() and finally get the new session from that request.
  3. Calling persistSession() again when we return the response so the new cookie is set.
  4. Wrapping PhpSessionPersistence so it checks for the existence of a session cookie before overwriting it with the now-useless proxied session ID, and injecting the wrapped instance into the SessionMiddeware.

There must be a better way. Why can’t I just $session->start()?

So I’d like two new interfaces:

interface StartableSessionInterface
{
    /**
     * Starts the session and returns session instance
     *
     * @return SessionInterface
     */
    public function start() : SessionInterface;
}

and

interface StartablePersistenceInterface
{
    /**
     * Starts the given session and returns started session instance
     *
     * @param SessionInterface $session
     * @return SessionInterface
     */
    public function start(SessionInterface $session) : SessionInterface;
}

PhpSessionPersistence would implement StartablePersistenceInterface. And LazySession would implement StartableSessionInterface, replacing its proxied session with the response from the persistence, if supported, or barfing if not.

I’ll do a PR for this. But I’d love to know if there’s a better approach.

What do you think?

I’ve realised that I don’t need to actually start the session - just initialise the ID. PRs are here: