Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Laravel Impersonate Laravel Package

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.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Steps

  1. Installation:

    composer require lab404/laravel-impersonate
    

    No additional configuration is required due to Laravel's auto-discovery.

  2. 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');
    
  3. Where to Look First:

    • Facade API: Focus on Impersonate::take(), Impersonate::leave(), and Impersonate::isImpersonating().
    • Blade Directives: @isImpersonating, @canImpersonate, @canBeImpersonated for UI integration.
    • Configuration: config/impersonate.php for redirect paths and authorization logic.
    • Events: Taken and Left events for auditing (register listeners in EventServiceProvider).

Implementation Patterns

Core Workflows

  1. 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');
    }
    
  2. 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
    }
    
  3. 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,
    ];
    
  4. 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
    ],
    
  5. 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
    
  6. 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,
        ],
    ];
    
  7. 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');
    }
    
  8. 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;
        });
    }
    
  9. 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);
    }
    
  10. 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');
    }
    

Gotchas and Tips

Pitfalls

  1. Session Driver Requirements:

    • Issue: Impersonation fails with array session driver.
    • Fix: Use file, database, or redis in .env:
      SESSION_DRIVER=file
      
  2. Guard Name Omission:

    • Issue: Impersonation defaults to the default guard if not specified, causing unexpected behavior in multi-guard setups.
    • Fix: Always specify the guard name when working with multiple guards:
      Impersonate::take($user, 'api'); // Explicit guard
      
  3. User Provider Validation:

    • Issue: findUserById throws MissingUserProvider or InvalidUserProvider exceptions if the guard lacks a valid user provider.
    • Fix: Ensure your guard has a valid user provider. For custom providers, override the resolver:
      $manager->setUserResolver(function ($id, $guard = null) {
          $guardInstance = auth()->guard($guard);
          return $guardInstance->provider()->retrieveById($id);
      });
      
  4. Session Expiration:

    • Issue: Impersonation session may expire unexpectedly, especially in long-running processes.
    • Fix: Extend session lifetime in config/session.php:
      'lifetime' => 120, // 2 hours
      
  5. Blade Directive Scope:

    • Issue: Blade directives may not work as expected in nested views or included partials.
    • Fix: Use helper functions (is_impersonating(), can_impersonate()) in complex views:
      @if(is_impersonating())
          <div class="alert alert-info">Impersonating...</div>
      @endif
      
  6. Middleware Order:

    • Issue: Impersonation checks may fail if middleware order is incorrect (e.g., impersonation middleware runs before auth).
    • Fix: Place impersonation-related middleware after authentication middleware in Kernel.php:
      protected $middleware = [
          // ...
          \App\Http\Middleware\CheckImpersonatePermission::class,
      ];
      
  7. Event Firing:

    • Issue: Events may not fire during impersonation if the ImpersonateManager is not properly bound.
    • Fix: Ensure events are subscribed in EventServiceProvider and that the ImpersonateManager is correctly bound in the container.
  8. CSRF Protection:

    • **Issue
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
davejamesmiller/laravel-breadcrumbs
artisanry/parsedown
christhompsontldr/phpsdk
enqueue/dsn
bunny/bunny
enqueue/test
enqueue/null
enqueue/amqp-tools
milesj/emojibase
bower-asset/punycode
bower-asset/inputmask
bower-asset/jquery
bower-asset/yii2-pjax
laravel/nova
spatie/laravel-mailcoach
spatie/laravel-superseeder
laravel/liferaft
nst/json-test-suite
danielmiessler/sec-lists
jackalope/jackalope-transport