Redirect after login

I’m following the documentation for authentication using mezzio-authentication-session that lives here:
https://docs.mezzio.dev/mezzio-authentication-session/v1/login-handler/

It works to log me in, but it doesn’t appear to properly redirect to the address I was at before the /login redirect

so for example,

  1. I go to mydomain.com/api/test
  2. It creates a session in the SessionMiddleware
  3. I see that the request->uri->path is ‘/api/test’
  4. It calls the AuthenticationMiddleware callable, which fails to authenticate, naturally, returning an unauthorizedResponse.
  5. This causes the a 302 Found response with a Location header of /login. There is no Referer Header
  6. The browser calls /login automatically
  7. It looks for the referer, and doesn’t find one. defaults to ‘/’
  8. It returns the login page to browser
  9. I fill out login form, and POST it
  10. Login succeeds and forwards the request to /

Is it the responsibility of the browser to send a Referer header or is it the responsibility of Mezzio to somehow tell the browser to submit it with the request to the new location?

If it is the responsibility of Mezzio, what am I missing from my code (I’m guessing I have to set the redirect into the session), and where should it go? LoginHandler is where I would expect, but it doesn’t get that far - it fails to authenticate first… but since it is redirecting to the login page, it appears to be behaving as expected. So, I’m not sure changing my pipeline order will help, though I have tried swapping the RouteMiddleware and the callable for the AuthenticationMiddleware, but it didn’t seem to help. Perhaps I should set it in the callable before it calls the AuthenticationMiddleware, but I don’t know. I feel like this should work just from the documentation example, since it specifically calls out the use case:
“Create a handler that will both display and handle a login form, redirecting to the originally requested location once a successful authentication occurs.”

$app->pipe(\Mezzio\Session\SessionMiddleware::class);
$app->pipe($factory->callable(
    function ($request, $handler) use ($container) {
        if ($request->getUri()->getPath() === '/login') {
            return $handler->handle($request);
        }
        $authenticationMiddleware = $container->get(
            Mezzio\Authentication\AuthenticationMiddleware::class
        );
        return $authenticationMiddleware->process($request, $handler);
    }
));
$app->pipe(RouteMiddleware::class);

Browser, which means that the information may be missing.

Does that mean that the PhpSession’s unauthorizedResponse needs to be sending a Referer header as well as a Location header?

public function unauthorizedResponse(ServerRequestInterface $request): ResponseInterface
{
    return ($this->responseFactory)()
        ->withHeader(
            'Location',
            $this->config['redirect']
        )
        ->withStatus(302);
}

Setting the Referer header didn’t work, because the browser will not forward the Referer to the following request to /login.

What appears to have worked, is adding the following to the PhpSession class’s unauthorizedResponse method:

$session  = $request->getAttribute('session');
$session->set('authentication:redirect', $request->getUri()->getPath());

This behaviour is correct.

Unfortunately, the idea is wrong. Editing the core files is a no-go and not needed.

Please check the handleLoginAttempt method of the login handler if you can set the variable there.
And before that you can check if the variable is already set.

Is this the accepted solution to this issue (modifying handleLoginAttempt?)

The LoginHandler class from the documentation is a part of your application and you can modify everything you need and like. It is an example.

You can also look at the issue tracker of mezzio-authentication-session, there you will find an alternative solution.
Add a comment or create your own feature request if you miss something. (Mezzio is a community-driven project and everyone here is part of that community! :smiley: )

Thank you for response!

The problem goes beyond changes to application-only code (LoginHandler). Modifying LoginHandler alone wouldn’t work, as information about the referrer is lost by the time the handler is invoked.

The problem was that the documented example uses PhPSession which doesn’t keep track of the referrer (as mentioned in the chat). The alternate solution replaced the PhpSession with a custom implementation.

I chose to code up a quick fix by extending PhpSession and over-riding unauthorizedResponse to implement the change suggested by @Brad_MacGregor. It was a bit of a hack to replicate a couple private members for the subclass - but it got me past the issue.

Thanks again, and appreciate the work done by your team!