lab404/laravel-impersonate
Add secure user impersonation to Laravel: let admins log in as other users for support and debugging, then easily leave impersonation. Includes middleware, routes/helpers, session-based tracking, and simple integration with your User model.
Installation:
composer require lab404/laravel-impersonate
php artisan vendor:publish --provider="Lab404\Impersonate\ImpersonateServiceProvider"
config/impersonate.php with default settings.First Use Case:
use Lab404\Impersonate\Facades\Impersonate;
public function impersonate(User $user) {
Impersonate::impersonate($user);
return redirect()->intended('/dashboard'); // Redirects as the impersonated user
}
Impersonate::stop();
return redirect()->intended('/admin');
Blade Directives (for UI):
@impersonatable
<button>Impersonate</button>
@endimpersonatable
@canimpersonate
<button>Stop Impersonating</button>
@endcanimpersonate
Middleware Protection:
Add to app/Http/Kernel.php:
'impersonate' => \Lab404\Impersonate\Middleware\ImpersonateMiddleware::class,
Impersonation Flow:
Impersonate::impersonate($user)->redirectTo('/user/dashboard');
Impersonate::stop() with a redirect back to admin view.Role-Based Access:
config/impersonate.php:
'roles' => ['admin', 'support'],
public function handle($request, Closure $next) {
if (!auth()->user()->hasRole(['admin'])) {
abort(403);
}
return $next($request);
}
Dynamic Redirects:
$originalUrl = url()->previous();
Impersonate::impersonate($user)->redirectTo($originalUrl);
Multi-Guard Support:
Impersonate::impersonate($user, 'api');
@impersonatable('api')
Audit Logging:
Listen to events in EventServiceProvider:
protected $listen = [
\Lab404\Impersonate\Events\ImpersonateStarted::class => [
\App\Listeners\LogImpersonation::class,
],
];
Testing:
Use Impersonate::impersonate() in PHPUnit:
public function test_as_user() {
Impersonate::impersonate($this->user);
$response = $this->get('/dashboard');
$response->assertSee('User Dashboard');
}
API Impersonation: For API-only apps, create a dedicated route:
Route::post('/impersonate', function (Request $request) {
$user = User::find($request->user_id);
Impersonate::impersonate($user);
return response()->json(['message' => 'Impersonating user']);
})->middleware('auth:api');
Session Timeout:
Configure in config/impersonate.php:
'timeout' => 900, // 15 minutes
Session Conflicts:
Impersonate::impersonate($user)->remember() to persist the session.Middleware Collisions:
VerifyCsrfToken or ThrottleRequests may fail during impersonation.except in HandleIncomingRequests:
protected $except = [
'impersonate/*',
];
Nested Impersonation:
Impersonate::isImpersonating() before proceeding:
if (!Impersonate::isImpersonating()) {
Impersonate::impersonate($user);
}
User Provider Errors:
findUserById fails if the guard’s user provider is misconfigured.provider in config/auth.php is correct:
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users', // Must match a provider
],
],
Blade Directive Scope:
@impersonatable may not render if the user lacks permissions.@can:
@can('impersonate')
@impersonatable
<button>Impersonate</button>
@endimpersonatable
@endcan
Check Impersonation Status:
dd(Impersonate::isImpersonating(), Impersonate::getImpersonator());
Log Events:
Add a listener to ImpersonateStarted/ImpersonateEnded:
public function handle($event) {
\Log::info('Impersonation started', [
'impersonator' => $event->user->id,
'impersonated' => $event->impersonatedUser->id,
]);
}
Clear Stale Sessions: If impersonation feels "stuck," manually clear the session:
session()->flush();
Custom User Resolution:
Override findUserById in a service provider:
public function boot() {
Impersonate::extend(function ($app) {
$app->bind(\Lab404\Impersonate\Contracts\ImpersonateUserProvider::class, function () {
return new CustomUserProvider();
});
});
}
Dynamic Role Checks:
Replace static role checks with a closure in config/impersonate.php:
'roles' => function ($user) {
return $user->isSuperAdmin() || $user->hasPermission('impersonate');
},
Post-Impersonation Actions: Trigger logic after stopping impersonation via an event listener:
public function handle($event) {
// Send notification to the impersonated user
$event->impersonatedUser->notify(new ImpersonationEnded);
}
Guard-Specific Config: Extend the config for multiple guards:
'guards' => [
'web' => ['timeout' => 900],
'api' => ['timeout' => 300],
],
timeout Value:
0 = No timeout.null = Uses session lifetime (default: 2 hours).redirect_to:
null, redirects to the original URL.'/dashboard').remember:
false).How can I help you explore Laravel packages today?