lab404/laravel-impersonate
Easily add user impersonation to Laravel apps. Let admins securely “log in as” another user, switch back anytime, and control access with middleware, policies, and guards. Supports multi-auth setups and integrates cleanly with existing authentication.
Installation:
composer require lab404/laravel-impersonate
No additional configuration is required due to Laravel's auto-discovery.
First Use Case: Impersonate a user via a controller method:
use Lab404\Impersonate\Facades\Impersonate;
public function impersonate(User $user)
{
Impersonate::take($user);
return redirect()->intended('/dashboard');
}
Add a route in routes/web.php:
Route::middleware(['auth'])->get('/impersonate/{user}', [AdminController::class, 'impersonate'])
->name('impersonate.start');
Where to Look First:
Impersonate::take(), Impersonate::leave(), and Impersonate::isImpersonating().@isImpersonating, @canImpersonate, @canBeImpersonated for UI integration.config/impersonate.php for redirect paths and authorization logic.Taken and Left events for auditing (register listeners in EventServiceProvider).Basic Impersonation Flow:
// Start impersonation with authorization check
public function startImpersonation(User $user)
{
if (!auth()->user()->can('impersonate-users')) {
abort(403);
}
Impersonate::take($user);
return redirect()->route('user.dashboard');
}
// Stop impersonation with redirect
public function stopImpersonation()
{
Impersonate::leave();
return redirect()->route('admin.dashboard')
->with('status', 'Impersonation ended');
}
Multi-Guard Impersonation:
// Impersonate using a specific guard (e.g., 'api')
Impersonate::take($user, 'api');
// Check impersonation status for a guard
if (Impersonate::isImpersonating('api')) {
// Custom logic for API impersonation
}
Authorization Middleware:
// app/Http/Middleware/CheckImpersonationPermission.php
public function handle($request, Closure $next)
{
if (Impersonate::isImpersonating() && !$request->user()->can('impersonate')) {
abort(403, 'Unauthorized to perform this action while impersonating.');
}
return $next($request);
}
Register in app/Http/Kernel.php:
protected $routeMiddleware = [
'can.impersonate' => \App\Http\Middleware\CheckImpersonationPermission::class,
];
Dynamic Redirects:
Configure in config/impersonate.php:
'redirect' => [
'path' => '/admin/dashboard',
'with' => ['flash' => 'You are no longer impersonating.'],
'intended' => true, // Redirect to intended URL if available
],
Blade UI Integration:
@isImpersonating
<div class="alert alert-info">
Impersonating: {{ auth()->user()->name }}
<a href="{{ route('impersonate.stop') }}" class="btn btn-sm btn-warning">End Impersonation</a>
</div>
@endisImpersonating
@canImpersonate($user)
<button class="btn btn-primary" onclick="window.location='{{ route('impersonate.start', $user) }}'">
Impersonate {{ $user->name }}
</button>
@endcanImpersonate
Event Listeners for Auditing:
// app/Providers/EventServiceProvider.php
protected $listen = [
\Lab404\Impersonate\Events\Taken::class => [
\App\Listeners\LogImpersonationStarted::class,
],
\Lab404\Impersonate\Events\Left::class => [
\App\Listeners\LogImpersonationEnded::class,
],
];
Testing Impersonation:
public function test_impersonation_flow()
{
$this->actingAs($admin)
->get("/impersonate/{$user->id}")
->assertRedirect('/dashboard');
$this->assertTrue(Impersonate::isImpersonating());
$this->assertEquals($user->id, auth()->id());
$this->get('/impersonate/stop')
->assertRedirect('/admin/dashboard');
}
Custom User Resolution: Override the user resolver in a service provider:
public function register()
{
$this->app->bind(\Lab404\Impersonate\Contracts\ImpersonateManager::class, function ($app) {
$manager = new \Lab404\Impersonate\ImpersonateManager($app['auth']);
$manager->setUserResolver(function ($id, $guard = null) {
return User::where('uuid', $id)->firstOrFail();
});
return $manager;
});
}
Impersonation in API Guards:
// Start impersonation for API guard
public function impersonateApiUser(User $user)
{
Impersonate::take($user, 'api');
return response()->json(['message' => 'Impersonating user'], 200);
}
// Middleware for API impersonation
public function handle($request, Closure $next)
{
if (Impersonate::isImpersonating('api')) {
$request->merge(['user' => auth()->user()]);
}
return $next($request);
}
Bulk Impersonation Actions:
public function impersonateMultiple(Request $request)
{
$request->validate(['users' => 'required|array']);
foreach ($request->users as $userId) {
$user = User::findOrFail($userId);
Impersonate::take($user);
// Perform actions as impersonated user
Impersonate::leave();
}
return back()->with('success', 'Bulk impersonation completed');
}
Session Driver Requirements:
array session driver.file, database, or redis in .env:
SESSION_DRIVER=file
Guard Name Omission:
Impersonate::take($user, 'api'); // Explicit guard
User Provider Validation:
findUserById throws MissingUserProvider or InvalidUserProvider exceptions if the guard lacks a valid user provider.$manager->setUserResolver(function ($id, $guard = null) {
$guardInstance = auth()->guard($guard);
return $guardInstance->provider()->retrieveById($id);
});
Session Expiration:
config/session.php:
'lifetime' => 120, // 2 hours
Blade Directive Scope:
is_impersonating(), can_impersonate()) in complex views:
@if(is_impersonating())
<div class="alert alert-info">Impersonating...</div>
@endif
Middleware Order:
Kernel.php:
protected $middleware = [
// ...
\App\Http\Middleware\CheckImpersonatePermission::class,
];
Event Firing:
ImpersonateManager is not properly bound.EventServiceProvider and that the ImpersonateManager is correctly bound in the container.CSRF Protection:
How can I help you explore Laravel packages today?