user(); if ($user !== null && ! $request->session()->has('impersonator_id')) { $customer = Customer::query()->where('user_id', $user->id)->first() ?? Customer::query()->where('email', $user->email)->first(); if ($customer !== null && ($customer->status === 'suspended' || $customer->status === 'closed' || $customer->closed_at !== null)) { Auth::logout(); // NOT session()->invalidate(): where the console and the portal // share a host (shared/fallback mode — this VM's own mode), both // guards keep their login key in the SAME session. invalidate() // is flush() + migrate(true) — it discards every attribute in the // session, not just the 'web' guard's, so it would silently sign // an operator elsewhere in that same browser out of the console // too. regenerate() issues a new session id (no fixation risk) // without touching the other attributes, so the 'operator' // guard's own login key — untouched by the Auth::logout() call // above, which only logs out the default ('web') guard — // survives untouched. Same fix as routes/admin.php's own // /logout route, mirrored the other way round. $request->session()->regenerate(); $request->session()->regenerateToken(); $key = $customer->closed_at !== null || $customer->status === 'closed' ? 'auth.account_closed' : 'auth.account_suspended'; return redirect()->route('login')->withErrors(['email' => __($key)]); } } return $next($request); } }