From 4341fc5d08291783a0b9fb913d55d8887fe3a3fb Mon Sep 17 00:00:00 2001 From: lukinovec Date: Tue, 3 Mar 2026 12:27:30 +0100 Subject: [PATCH 1/3] Instead of setting the 'tenancy_impersonating' session variable, store auth guard in 'tenancy_impersonation_guard' Also make `stopImpersonating()` able to keep the user logged in. --- src/Features/UserImpersonation.php | 16 ++++++++++------ tests/TenantUserImpersonationTest.php | 8 ++++---- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/src/Features/UserImpersonation.php b/src/Features/UserImpersonation.php index d286b8ba..91bb6789 100644 --- a/src/Features/UserImpersonation.php +++ b/src/Features/UserImpersonation.php @@ -61,9 +61,9 @@ class UserImpersonation implements Feature Auth::guard($token->auth_guard)->loginUsingId($token->user_id, $token->remember); - $token->delete(); + session()->put('tenancy_impersonation_guard', $token->auth_guard); - session()->put('tenancy_impersonating', true); + $token->delete(); return redirect($token->redirect_url); } @@ -76,16 +76,20 @@ class UserImpersonation implements Feature public static function isImpersonating(): bool { - return session()->has('tenancy_impersonating'); + return session()->has('tenancy_impersonation_guard'); } /** * Logout from the current domain and forget impersonation session. */ - public static function stopImpersonating(): void + public static function stopImpersonating(bool $logout = true): void { - auth()->logout(); + if ($logout) { + $guard = session()->get('tenancy_impersonation_guard'); - session()->forget('tenancy_impersonating'); + auth($guard)->logout(); + } + + session()->forget('tenancy_impersonation_guard'); } } diff --git a/tests/TenantUserImpersonationTest.php b/tests/TenantUserImpersonationTest.php index ea679357..e252ddc7 100644 --- a/tests/TenantUserImpersonationTest.php +++ b/tests/TenantUserImpersonationTest.php @@ -89,13 +89,13 @@ test('tenant user can be impersonated on a tenant domain', function () { ->assertSee('You are logged in as Joe'); expect(UserImpersonation::isImpersonating())->toBeTrue(); - expect(session('tenancy_impersonating'))->toBeTrue(); + expect(session('tenancy_impersonation_guard'))->toBe($token->auth_guard); // Leave impersonation UserImpersonation::stopImpersonating(); expect(UserImpersonation::isImpersonating())->toBeFalse(); - expect(session('tenancy_impersonating'))->toBeNull(); + expect(session('tenancy_impersonation_guard'))->toBeNull(); // Assert can't access the tenant dashboard pest()->get('http://foo.localhost/dashboard') @@ -135,13 +135,13 @@ test('tenant user can be impersonated on a tenant path', function () { ->assertSee('You are logged in as Joe'); expect(UserImpersonation::isImpersonating())->toBeTrue(); - expect(session('tenancy_impersonating'))->toBeTrue(); + expect(session('tenancy_impersonation_guard'))->toBe($token->auth_guard); // Leave impersonation UserImpersonation::stopImpersonating(); expect(UserImpersonation::isImpersonating())->toBeFalse(); - expect(session('tenancy_impersonating'))->toBeNull(); + expect(session('tenancy_impersonation_guard'))->toBeNull(); // Assert can't access the tenant dashboard pest()->get('/acme/dashboard') From c48aed940650f255ba2b6e379b5f81de51f20409 Mon Sep 17 00:00:00 2001 From: lukinovec Date: Tue, 3 Mar 2026 12:28:42 +0100 Subject: [PATCH 2/3] Test that `stopImpersonating()` can keep the user authenticated --- tests/TenantUserImpersonationTest.php | 41 +++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/tests/TenantUserImpersonationTest.php b/tests/TenantUserImpersonationTest.php index e252ddc7..2e9b3c3a 100644 --- a/tests/TenantUserImpersonationTest.php +++ b/tests/TenantUserImpersonationTest.php @@ -148,6 +148,47 @@ test('tenant user can be impersonated on a tenant path', function () { ->assertRedirect('/login'); }); +test('stopImpersonating can keep the user authenticated', function() { + makeLoginRoute(); + + Route::middleware(InitializeTenancyByPath::class)->prefix('/{tenant}')->group(getRoutes(false)); + + $tenant = Tenant::create([ + 'id' => 'acme', + 'tenancy_db_name' => 'db' . Str::random(16), + ]); + + migrateTenants(); + + $user = $tenant->run(function () { + return ImpersonationUser::create([ + 'name' => 'Joe', + 'email' => 'joe@local', + 'password' => bcrypt('secret'), + ]); + }); + + // Impersonate the user + $token = tenancy()->impersonate($tenant, $user->id, '/acme/dashboard'); + + pest()->get('/acme/impersonate/' . $token->token) + ->assertRedirect('/acme/dashboard'); + + expect(UserImpersonation::isImpersonating())->toBeTrue(); + + // Stop impersonating without logging out + UserImpersonation::stopImpersonating(false); + + // The impersonation session key should be cleared + expect(UserImpersonation::isImpersonating())->toBeFalse(); + expect(session('tenancy_impersonation_guard'))->toBeNull(); + + // The user should still be authenticated + pest()->get('/acme/dashboard') + ->assertSuccessful() + ->assertSee('You are logged in as Joe'); +}); + test('tokens have a limited ttl', function () { Route::middleware(InitializeTenancyByDomain::class)->group(getRoutes()); From 20044a878b5427d7cd571b0e70119218d49c30da Mon Sep 17 00:00:00 2001 From: Samuel Stancl Date: Tue, 3 Mar 2026 23:00:31 +0100 Subject: [PATCH 3/3] tests: use literal value in auth guard assertion --- tests/TenantUserImpersonationTest.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/TenantUserImpersonationTest.php b/tests/TenantUserImpersonationTest.php index 2e9b3c3a..f9fed8ae 100644 --- a/tests/TenantUserImpersonationTest.php +++ b/tests/TenantUserImpersonationTest.php @@ -89,7 +89,8 @@ test('tenant user can be impersonated on a tenant domain', function () { ->assertSee('You are logged in as Joe'); expect(UserImpersonation::isImpersonating())->toBeTrue(); - expect(session('tenancy_impersonation_guard'))->toBe($token->auth_guard); + expect(session('tenancy_impersonation_guard'))->toBe('web'); + expect($token->auth_guard)->toBe('web'); // Leave impersonation UserImpersonation::stopImpersonating(); @@ -135,7 +136,8 @@ test('tenant user can be impersonated on a tenant path', function () { ->assertSee('You are logged in as Joe'); expect(UserImpersonation::isImpersonating())->toBeTrue(); - expect(session('tenancy_impersonation_guard'))->toBe($token->auth_guard); + expect(session('tenancy_impersonation_guard'))->toBe('web'); + expect($token->auth_guard)->toBe('web'); // Leave impersonation UserImpersonation::stopImpersonating();