Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

johnvoncolln's avatar

Shopping cart session data and remember me conflicts

I'm on Laravel 10.x and using Fortify

I have a shopping cart that is storing cart contents in session data. I would like to limit session to 120 minutes, but allow registered users to use remember me. The problem is that when session expires and registered user returns to cart, they are logged in of course, but session data is gone.

How can I have Laravel check if user has remember_me token and just NOT invalidate session data? Or, where is this login action and can I, or how do I, override it? Maybe auth middleware?

0 likes
22 replies
LaryAI's avatar
Level 58

To address the issue of session data being invalidated while still keeping the user logged in with the "remember me" feature, you can take a couple of approaches. One way is to store the cart data in a more persistent storage like the database or cache, associated with the user's ID. Another way is to extend the session lifetime conditionally for users who are authenticated via the "remember me" cookie.

Here's a solution that involves storing the cart in the database or cache, which is more persistent than session storage:

  1. Create a table or use a cache to store cart data, linking it to the user's ID.
  2. When a user adds an item to the cart, save it to this storage instead of the session.
  3. When a user visits the cart page, retrieve the cart data from this storage.

Here's an example of how you might implement this using a database:

First, create a migration for the cart table:

php artisan make:migration create_carts_table

In the migration file, define the structure:

Schema::create('carts', function (Blueprint $table) {
    $table->id();
    $table->unsignedBigInteger('user_id');
    $table->text('cart_data'); // This could be a JSON column if your database supports it
    $table->timestamps();

    $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
});

Run the migration:

php artisan migrate

Next, whenever you need to save or update the cart data, you would do something like this:

use App\Models\Cart;

// Assuming you have a Cart model and $cartData is the data you want to store
$user = auth()->user();
$cart = Cart::updateOrCreate(
    ['user_id' => $user->id],
    ['cart_data' => json_encode($cartData)]
);

When you need to retrieve the cart data:

$cart = Cart::where('user_id', auth()->id())->first();
$cartData = json_decode($cart->cart_data, true);

If you prefer to use the cache, you can use Laravel's Cache facade to store and retrieve the cart data:

use Illuminate\Support\Facades\Cache;

// To store the cart data
Cache::put('cart_' . auth()->id(), $cartData, now()->addMinutes(120));

// To retrieve the cart data
$cartData = Cache::get('cart_' . auth()->id());

Remember to handle the logic for when the user logs out, you may want to clear the cart data from the database or cache.

This approach ensures that the cart data persists beyond the session lifetime and is available as long as the user is remembered via the "remember me" feature.

DanteB918's avatar

If the user is logged in, then you should be persisting the cart instead of trying to stick it in the session. as long as you have a user_id column and proper relationships for the cart order's table to user's table, then none of your logged in user's carts will go missing whether they are logged in or not. Just have a "Would you like to continue your order?" or something when they log back in, and if they opt out, just delete that order and make them start a new one. I'm sure there are plenty of ways to go about it though. Is there a particular reason you decided to store in the session?

johnvoncolln's avatar

The package I'm using stores cart data in the session, so this isn't an option unfortunately.

johnvoncolln's avatar

Like my original question, just trying to figure out if I can intercept the login request and NOT invalidate the session if remember_token is true on the user...

gych's avatar

Before setting the session time check if the user has remember_me checked. Only if not checked set limited session time of 120min.

gych's avatar

@johnvoncolln Its better to store the card data in the DB but since that's not possible with the package you're using, you could try setting the session via a middleware that checks if the user has remember_me checked. I can't 100% confirm if this will work since I haven't used this approach myself but t's worth to try.

Which package are you exactly using?

johnvoncolln's avatar

@gych https://cartalyst.com/manual/cart/8.x

I've already implemented logic to serialize the cart data and store in the DB for logout/login. So it basically serializes the data on log out and syncs back to session on login. I'm doing this by overriding PrepareAuthenticatedSession::class in the FortifyServiceProvider, but this is not hit when a user is utilizing remember me.

I'm also trying to implement an abandoned cart system to notify customers days or weeks later, so I'm having to serialize expiring session cart data, but I don't like it. I may end up just making session_lifetime and remember both 2 weeks, though I'm not crazy about this solution either...

DanteB918's avatar

I would go to config/auth.php and set ‘remember’ => 120, then go to config/session.php and set ‘lifetime’ => 120

Now they should both expire at the same time, (2 hours)

But I'd highly recommend to save the carts somewhere other than the session if possible

johnvoncolln's avatar

@DanteB918 Yes I could do that, but I want session to expire at 120 minutes, but remember me to last for 10 days.

Snapey's avatar

if they are using remember me, then you know who they are and can store the information in a pending carts table and restore it later

If they are not registered users then remember me is not even an option, and you should store the card client side in a cookie, or in a pending cart table identified by a cart cookie you give the visitor the first time they put something in the basket

Restoring pending cart to session can happen in response to an authenticated event, which fires at both normal login and as a result of remember me. Dont waste your time with logout as people rarely logout, they just close their device and walk away. Instead, update your copy of the cart each time it changes.

johnvoncolln's avatar

@Snapey I have logic built already that will serialize and store a cart in the database and can resync it with a session on login. One of the issues I'm facing is when people DON'T logout, I still need to capture and store the cart data. OR do it right before the session gets regenerated. No one seems to know where I can tap into the auth process for the remember me functionality.

martinbean's avatar

@johnvoncolln You shouldn’t be trying to use the session to store something like a cart that needs to persist between logging in/out, because the session is regenerated between log ins/log outs to prevent session fixation attacks.

Unfortunately, if that’s the approach the package has taken then you either need to configure a different storage mechanism (i.e. cookies) if it allows; or use a more appropriate package that doesn’t rely on vulnerable behaviour.

1 like
johnvoncolln's avatar

@martinbean can you explain what vulnerability I would be exposing by storing cart data in the session? Yes, jacking with sessions and trying to override any session invalidation could be seen as vulnerable, but what exactly is dangerous about storing cart data in the session?

martinbean's avatar

@johnvoncolln I literally named the vulnerability in my comment…

It’s not that storing cart data itself is dangerous. It’s that persisting session data between authenticated and unauthenticated requests can be the cause of “leaking” sensitive information, and Laravel—as a security-conscious framework—mitigates this by regenerating the session between log ins and log outs. That means session data is lost, including your cart.

So, as also mentioned in my comment, you will need to use an alternative storage mechanism to persist your cart across unauthenticated and authenticated requests, such as in a cookie.

johnvoncolln's avatar

Thanks for bringing attention to session fixation attacks - this is not something that I was aware of before and I'm not planning on messing with sessions. Previously in this discussion I mentioned that I've already built out logic that serializes the cart data and saves it for later syncing or retrieval. The challenge that I'm faced with now is:

A. Understanding how the remember me function logs back in and regenerates the session (so I can sync back cart data when user comes back)

B. An eloquent way of saving cart data to the db from idle sessions (right now I have a job that finds sessions older than X that have partially started checkout, or it's a user)

Ideally the cart package would just write to the DB, but this is a minor inconvenience that I can overcome compared to the other benefits and ease of use the cart package brings.

Snapey's avatar

@johnvoncolln no, you are trying to solve the wrong issue.

when you connect to the site, you are given a session. When you login your session is regenerated, and you can save data in the session. as long as you keep presenting a valid session cookie then you will keep being matched to the same session.

But then you go away. You stop talking to the server and after the session lifetime has elapsed, your session on the server is stale. Whilst it might still exist, it is candidate for session cleanup - the process of deleting stale sessions. If the session expires then you can consider that data gone - it does not matter how you login again, you will never be re-paired with the previous session.

When you come back 4 hours later, your session cookie is no longer valid, but you do have a remember me cookie. This is an authentication token for a user account, and if it is valid, then you are simply authenticated as that user, and start with a fresh session.

As I mentioned before, you should listen to the authenticated event and restore session data when it fires. If that is by full login or remember me is not relevant.

johnvoncolln's avatar

@Snapey The part about saving cart data from idle sessions was my intention of building an abandoned cart email system, but I'm just going to pull the data from the carts saved to the DB - there's more, complex reasons why I was considering scraping old sessions that have to do with the limited event system on the cart package, but I'm working around that.

To address the other issue about resyncing cart data with the new session, and this is probably edge case, but who doesn't love a good edge case, if a user begins an order, has several items in their cart, then logs in and has a saved cart - we need to merge unauthenticated cart contents with saved cart contents. You can't do that with the login event, but have to see if it's possible with authenticated event. I need access to the current session before it's regenerated when a user logs in to grab the unauthenticated cart.

I have the merge cart logic working by using custom authentication in FortifyServiceProvider using Fortify::authenticateThrough(), but the Remember me doesn't hit this when logging in. I'll investigate the authenticated event to see if I can stick it in there.

martinbean's avatar

I'm not planning on messing with sessions.

@johnvoncolln You may not be. But bad actors will try.

A. Understanding how the remember me function logs back in and regenerates the session (so I can sync back cart data when user comes back)

You can’t. The session is regenerated. Anything that was in the session is lost.

martinbean's avatar

@johnvoncolln I don’t know why you’re getting snippy. I’ve told you like, four times that the session is regenerated. The code from Fortify which do so:

https://github.com/laravel/fortify/blob/0c1721f0e50dd63fa3a4b4ad7ade553b821ec015/src/Actions/PrepareAuthenticatedSession.php#L36-L38

Anything that was in the session, is lost because you‘re given a new session on log in/log out. The logout action too, for avoidance of doubt:

https://github.com/laravel/fortify/blob/0c1721f0e50dd63fa3a4b4ad7ade553b821ec015/src/Http/Controllers/AuthenticatedSessionController.php#L104-L107

So, yet again (although not quite for the fourth time yet I don’t think): you need to store your cart identifier somewhere other than the session if you want it to be available across logging in and out.

1 like
johnvoncolln's avatar

@martinbean Not trying to be snippy, but you seem to be arguing a point that I don't disagree with. I understand how sessions work and that the session is regenerated, there's no denying that.

In just the previous post, I wrote that I'm saving my cart data in the database. I'm not sure how to be more explicit about it.

Maybe you could expand on whatever it is you're thinking so I can understand

Please or to participate in this conversation.