jetstream: Inertia - Expired session causes the website to be displayed in a modal

  • Jetstream Version: 1.0.2
  • Laravel Version: 8.0.1
  • PHP Version: 7.4.7
  • Database Driver & Version: mysql Ver 14.14 Distrib 5.7.29, for osx10.15
  • Stack: Inertia

Description:

When the session expires the user doesn’t get redirected to the login page, but instead this page is shown as a modal. After logging in within the modal the website is shown inside the modal.

Steps To Reproduce:

  • Create a new Laravel + Jetstream project using laravel new saas --jet --stack=inertia --teams
  • Register an account
  • When logged in, open your preferred devtools and delete the laravel_session cookie
  • Click on a link, for example in the user-dropdown click on “Profile”
  • A modal is now shown with the login page
  • When logging in within the modal the site will be displayed inside the modal

About this issue

  • Original URL
  • State: closed
  • Created 4 years ago
  • Reactions: 7
  • Comments: 20 (12 by maintainers)

Most upvoted comments

Related https://github.com/inertiajs/inertia-laravel/issues/57 (and potential solution https://github.com/inertiajs/inertia-laravel/issues/57#issuecomment-570581851). Perhaps something that wouldn’t be too difficult to take care of by overwriting \Illuminate\Foundation\Exceptions\Handler::unauthenticated.

This worked for me:

protected function unauthenticated($request, AuthenticationException $exception)
{
    if ($request->inertia()) {
        return response('', 409)->header('X-Inertia-Location', $exception->redirectTo() ?? route('login'));
    }

    return parent::unauthenticated($request, $exception);
}

I know this is closed but I’ve finally pushed my project into production and this became an issue where it wasn’t in development. Here’s what I did to fix it. I placed this code in the Authenticate.php middleware and removed the default and it worked perfectly:

if (! $request->expectsJson() && $request->inertia()) { abort(409, '', ['X-Inertia-Location' => url()->route('login')]); } else if (! $request->expectsJson()) { return route('login'); }

I haven’t upgraded inertia yet and don’t plan on it until things become more stable with the entire laravel/jetstream/inertia stack so this works for now. Hope it helps someone!

It seems to me that doesn’t matter, because that’s meant for error pages. What happens is the following:

  • I keep the webpage open after I logged in, session has expired (or delete the cookie), which means the I’m no longer logged in
  • I click on a link, for example “Profile” or “Dashboard”
  • Inertia fetches the page (ex. /dashboard), this page will redirect (302) to the login page
  • Since the login page is not an Inertia response it will be rendered in the Inertia “error” modal

However, this behaviour is not typical error behaviour to me. I expect the user to be redirected to the login page, not a modal that shows the login page

I think this issue can be closed now, as this will be fixed in the 2.x release of Jetstream since #298 is now merged into master.

This issue is caused by the the auth pages which currently return a blade view. In 2.x all of Jetstreams auth pages will be Inertia responses. When a middleware then redirects to the login page it should render correctly.

Related inertiajs/inertia-laravel#57 (and potential solution inertiajs/inertia-laravel#57 (comment)). Perhaps something that wouldn’t be too difficult to take care of by overwriting \Illuminate\Foundation\Exceptions\Handler::unauthenticated.

This worked for me:

protected function unauthenticated($request, AuthenticationException $exception)
{
    if ($request->inertia()) {
        return response('', 409)->header('X-Inertia-Location', $exception->redirectTo() ?? route('login'));
    }

    return parent::unauthenticated($request, $exception);
}

This didn’t work for me because it seemed like the unauthenticated function was not being called. I had to do this instead:

/**
 * Prepare exception for rendering.
 *
 * @param $request
 * @param \Throwable $e
 * @return \Illuminate\Http\JsonResponse|\Illuminate\Http\Response|\Symfony\Component\HttpFoundation\Response
 * @throws Throwable
 */
public function render($request, Throwable $e)
{
    $response = parent::render($request, $e);

    if ($response->status() === 419) {
        $location = $e instanceof AuthenticationException ? $e->redirectTo() : route('login');
        return response('', 409)->header('X-Inertia-Location', $location);
    }

    return $response;
}

Understood buddy! Maybe I’m just misunderstanding. My understanding is that once Jetstream is installed, all the views are published to your /resources folder, meaning changing this in 1.x wouldn’t impact anyone currently using Jetstream. Is that wrong?

Yes, we could do an Inertia::location($url) visit. However, to me, the better way to fix this is using all Vue page components, instead of using any Blade views for the Inertia.js stack.

@claudiodekker has already done this work, which you can find here: #298. However, I can see that it has been tagged for the 2.x release. I don’t really see how this is a breaking change though (correct me if I’m wrong @driesvints), so I actually think it would be better to just merge this into 1.x.

@driesvints Happy to look into this for you. Give me a couple days.

I’m actually hoping to also submit a PR to Jetstream for some recent updates to Inertia.js as well.

I’ll be in touch. 👍