Flash Messages not working everywhere

I’ve created a Slim Skeleton using Slim 4 and Slim Flash. I have flash messages working on every route except for the activation. I have read and reread every controller, written and rewritten the failing controller and still the flash messages don’t persist beyond the controller. When the page is rendered, it’s as if the messages were never in the session(they are in the session before returning the response).

I am very new to Slim, so figuring out the issue is beyond my current knowledge. I would appreciate any insight you guys could offer that might lead me to a resolution.

public function __invoke(ServerRequestInterface $request, ResponseInterface $response)
{
    $params = array_clean($request->getQueryParams(), [
        'email',
        'code',
    ]);

    if (!$this->activationCodeExists($user = User::whereEmail($email = $params['email'] ?? null)
        ->first(), $code = $params['code'] ?? null)) {
        $this->logger->error('Invalid activation code.');
        // TODO fix why this does not display on page load
        $this->flash->addMessage('error', 'Invalid activation code.');

        return $response->withHeader('Location', $this->routeParser->urlFor('home'));
    }

    Sentinel::getActivationRepository()->complete($user, $code);
    $role = Sentinel::findRoleByName('User');
    $role->users()->attach($user);

    // TODO fix why this does not display on page load
    $this->flash->addMessage('success', 'Your email has been confirmed and your account has been activated. You can now sign in.');

    return $response->withHeader('Location', $this->routeParser->urlFor('auth.signin'));
}

Hi @darkalchemy

The slim/flash package requires a started session.

Have you tried: session_start();

Also make sure that you save the session at the end with

session_write_close();

Thank you @odan for the reply. Yes, the session is started, flash messages is working on every other route I have created, just not this one.

How many redirects happens when you go to auth.signin ? There’s something that clears the session.

@Manrix thanks for the reply. There is 1 redirect if the user is already logged in.

Even if I change the route from auth.sign[up|in] to home(which has no redirects), the result is the same. No flash messages in the session.

If I drop a dd($_SESSION) in the index or __invoke methods the session doesn’t include the flash messages that were just inserted before the showing the response.

What is driving me crazy is I’m doing the exact same thing as every other route that sets a flash message and they work. The only difference here is that the page is being loaded from a link in an email.

I think I may have found the issue. I have a piece of middleware that grabs the query params from the request. I changed it to only add them if they are not empty and the flash messages are working as expected.

Now, I just need to understand why that middleware was removing/replacing the current flash messages.

Thanks to everyone for your comments.

Looks like I was mistaken, its still not working for only this one route. I will have to try debugging and step through the code if that’s even possible in phpstorm.

There is always more to learn:)

I found the issue and I should have seen this before now.

In the session, I set the samesite to ‘Strict’. So, when you click the link in the email the site opens and the session is started without access to the users cookies, so it can’t set the session.cookie. Then, on return the response and the site app runs again, it’s now a local request and samesite ‘Strict’ is allowed access to the users cookies, but the session flash object is empty, so the flash message is not displayed to the user.

This can be verified by checking your session files and there are 2 created from the 1 click in the email. The first has the flash messages, the second does not.

So, if you are going to send links to users to click and you need flash messaging to work, you have to use samesite ‘Lax’.

At least, I can’t think of anyway around this.

Any ideas?

After some thought, I’m wondering why I’m returning a response and why the response cycles through the app a second time instead of just rendering the view. I’m obviously doing something wrong and it’s not making any sense to me.

Does returning a response equate to a redirect? If so, then it makes sense that its cycling through the app twice. Update: According to the docs, using withHeader(‘Location’) is a redirect

Always more questions. Any help would be appreciated.

Thanks