Start a Project

How a Cross-Site POST Silently Resets Your Laravel Session

A shopper pays, returns to your store, and is suddenly logged out.

Their cart is empty, their session is gone, and no error was ever thrown.

We hit this on a Bagisto store during a Stripe payment redirect.

The cause was not Stripe. It was one cross-site POST and a cookie rule we all forget.

 

The Symptom: Logged Out After Paying

The payment succeeds on the gateway, then the shopper lands back on your domain.

From that request onward, auth() sees a guest. The old session id is simply gone.

Nothing in your logs looks wrong, because technically nothing failed.

 

The Cause: SameSite=Lax Withholds Your Cookie

Laravel signs users in with a session cookie. Bagisto ships it as SameSite=Lax.

Lax has one rule that matters here, and it is very easy to overlook.

The browser sends a Lax cookie on same-site requests and on cross-site top-level GET.

It does NOT send it on a cross-site POST. That is the whole bug in one sentence.

When a gateway POSTs the shopper back to your site, the session cookie is withheld.

 

What Laravel Does With a Missing Cookie

The return request now arrives with no session cookie. Laravel does not error.

StartSession reads the cookie, finds nothing, and starts a fresh, empty session.

Then it writes that new session back to the browser on the very same response.

That Set-Cookie uses the same cookie name, so it overwrites the authenticated one.

The browser keeps the new empty cookie, and every later request is now a guest.

Browser-cookie-flow-and-session-overwrite

 

The Fix: Never Depend on a Cross-Site POST for Identity

The reliable fix is to bring the shopper back with a top-level GET, not a POST.

A GET top-level navigation is exactly the case where Lax still sends the cookie.

Keep gateway-to-server callbacks stateless, and out of the browser session entirely.

A webhook or IPN is a server-to-server POST. It must never read or write that session.

If a cross-site POST return is truly unavoidable, do not trust the cookie at all.

Carry a short-lived signed token in the URL and rebuild identity from it server-side.

 

What About SameSite=None?

Setting the cookie to SameSite=None; Secure does let it survive a cross-site POST.

But it re-opens the CSRF surface that Lax was protecting, and it forces HTTPS.

Treat it as a last resort, not a fix. Prefer a GET return and stateless callbacks.

 

Key takeaways

1. A cross-site POST drops your SameSite=Lax session cookie.

2. Laravel then mints a new empty session and overwrites the old cookie.

3. The shopper is logged out silently, with nothing in the logs.

4. Bring users back with a top-level GET, so the Lax cookie is sent.

5. Keep webhooks and IPNs stateless and off the browser session.

 

Thank You for Reading!

You now understand how one cross-site POST can quietly reset a Laravel session.

Audit your payment returns, keep identity on GET, and keep callbacks stateless.

If you have questions, suggestions, or feedback, we would love to hear from you.

Leave a comment below, and we will be happy to help.

You can also explore our Bagisto Extensions.

If you are planning to build with Laravel, consider hiring laravel developers.

Exit mobile version