Weave 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 Impersonator Laravel Package

genealabs/laravel-impersonator

GeneaLabs Laravel Impersonator lets trusted admins securely sign in as another user for support and debugging. It offers configurable guards, middleware, Blade helpers, and simple routes to start and stop impersonation without exposing passwords.

View on GitHub
Deep Wiki
Context7

Getting Started

1. Match the version line before you install. This package co-versions with Laravel majors: ^13.0 targets Laravel 13 (PHP 8.5 in CI as of 13.0.0), and 10.x is the prior line — there is no 11.x/12.x tag. Check the README support table first, then:

composer require genealabs/laravel-impersonator

2. Publish config and views using the provider tag (don't guess the path):

php artisan vendor:publish --provider="GeneaLabs\LaravelImpersonator\LaravelImpersonatorServiceProvider"

You get config/impersonator.php, which holds the guard allowlist, redirect targets, and takeover behavior. Open this file first whenever behavior looks wrong.

3. Add the impersonation trait to every model that participates — normally App\Models\User, sometimes a separate Admin model. Add CanImpersonate to actors and CanBeImpersonated to targets (or the combined Impersonatable trait if one model plays both roles). The trait exposes impersonate($user) / stopImpersonating() plus canImpersonate() / canBeImpersonated() hooks you will override on day one.

4. Verify session middleware on the routes involved. The swap is written to and read from the session. Without StartSession and the auth guard resolving before your impersonation code runs, identity silently reverts on the next request — this is the number-one "it doesn't work" report.

5. Build the smallest useful loop before anything else:

  • A "Log in as this user" affordance (Nova action, or a POST route in your admin panel)
  • Redirect into the app
  • A sticky "You are impersonating X — stop" banner
  • A POST to stop that restores the original admin

Get that round trip green, then add audit logging, approval workflows, and environment gating.

Where to look first when inheriting this integration: config/impersonator.php, the User model's trait overrides, the layout banner partial, and the route middleware group. Those four places are essentially the whole integration.

Debugging checklist when the swap is a no-op: (a) is the route in the web group? (b) does the session driver actually persist (array/cookie won't between requests)? (c) is cached config stale? (d) does the guard in config match the guard your app reads? In tinker, inspect the session keys after a start call — if they aren't there, the middleware chain is wrong, not the package.

Implementation Patterns

Nova action as the primary entry point. This is the package's sweet spot. Expose impersonation from the user resource so support staff never leave the admin UI, and gate visibility with Nova's canSee/authorize so only the right roles see the button. Add a confirmation dialog — impersonation changes who you are, and a mis-click is expensive.

Controller + named route outside Nova. For Blade admin panels, keep it POST-only and policy-gated:

Route::post('/impersonate/{user}', [ImpersonationController::class, 'start'])
    ->middleware(['auth', 'can:impersonate,user'])
    ->name('impersonate.start');

Route::post('/impersonate/stop', [ImpersonationController::class, 'stop'])
    ->middleware('auth')
    ->name('impersonate.stop');

The package handles the session swap; authorization and redirects are yours. Redirect immediately after calling — don't keep composing a response in the same request (see gotchas).

Centralize both sides of the gate on the model. Don't scatter checks across Nova actions, controllers, and artisan commands:

public function canImpersonate(): bool
{
    return $this->hasRole('support')
        && $this->hasConfirmedTwoFactor();
}

public function canBeImpersonated(): bool
{
    return ! $this->isAdmin()
        && ! $this->isSystemAccount()
        && $this->isActive();
}

canBeImpersonated() is where you exclude other admins, service accounts, and deactivated users. One rule, every entry point, consistent behavior.

Banner partial in the main layout. Check the impersonation session flag and render a sticky, visually loud bar showing the target's name and avatar plus a "Stop impersonating" form posting to your stop route. The failure mode you're defending against is an admin acting on the wrong account — make it impossible to miss.

Wrap start/stop in a thin internal service with audit logging. The package is deliberately thin and gives you no trail. A small ImpersonationService (or event listeners) should record impersonator_id, target_id, ip, user_agent, optional reason, and timestamps. Log stop as well as start — a start with no stop is an ambiguous session window during incident review.

Test the session, not actingAs(). actingAs() bypasses the impersonation session keys entirely, so tests pass while the feature is broken. In feature tests: authenticate the admin normally, hit the real POST route, assert the identity swapped, then hit the stop route and assert the original admin is restored. Regressions live in the stop path.

Environment guard as a config-level switch. Disable impersonation in production, or restrict it to an allowlist of impersonator emails. A sensible default for an internal tool: on in staging, explicit allowlist in prod, and a config flag you can flip without a deploy.

Compose around the trait for per-tenant behavior. If impersonation must be scoped to a tenant, override the hooks and check tenant membership rather than forking the package. Add a request-scoped "current impersonation" accessor in your own code so views, policies, and logs don't each re-implement the check.

Upgrade workflow. A Laravel major upgrade now implies an impersonation-package bump in the same release train. Put it on the upgrade checklist next to other framework-coupled pins. 13.0.0 is compatibility-only (Laravel 13 + PHP 8.5 in CI) with no documented behavior changes, but the 10 → 13 jump means intermediate releases can't be reasoned about — diff vendor/ if behavior matters to you.

Gotchas and Tips

  • Middleware ordering. Impersonation middleware must run after StartSession and after the auth guard resolves. Register it in the web group rather than bolting it onto individual routes; misfiled middleware means the session has nothing to read.
  • auth()->user() is stale within the starting request. After calling impersonate(), the resolved user may still be the old model for the rest of that request. Redirect immediately; don't keep rendering as the new identity.
  • Multi-guard apps need explicit config. If you run admin and web guards, list the allowed guards in config/impersonator.php. A mismatch writes the swap to a guard nothing reads — a silent no-op that looks like a middleware bug.
  • Never use GET. A GET /impersonate/5 is either blocked or, worse, becomes a CSRF-able identity swap. Always POST, always CSRF-protected, always confirmed.
  • Logout while impersonating. If the impersonated user clicks "logout", they can destroy the impersonator's session and lose the original identity. Intercept logout in the banner flow and route it to "stop impersonating" instead.
  • Config caching. After editing config/impersonator.php, run config:cache in production and config:clear in development. Stale cached config is the most common "the middleware isn't firing" cause and it costs an hour every time.
  • Guard against recursion and self-impersonation. Explicitly prevent starting an impersonation while already impersonating, and prevent impersonating yourself. Otherwise stopImpersonating() can restore the wrong identity — and the bug only surfaces in the second-order case.
  • Step-up auth is your job. The impersonator should have already cleared whatever 2FA or password confirmation your app mandates. A remembered session alone must not unlock impersonation. Bake this into canImpersonate().
  • Session driver caveat. With array or cookie drivers — common in tests and some API setups — impersonation state vanishes between requests. Verify the driver before filing a bug; it's almost always the session, not the package.
  • Extend, don't fork. Config and views are publishable; the trait methods are overridable. Customize the banner markup and redirect defaults in your own app. Edits to vendor/ disappear on the next composer update.
  • Pin the version. Align the constraint with your Laravel major (^13.0 on Laravel 13). With no ^11/^12 line, verify compatibility on older frameworks yourself rather than trusting a constraint to resolve correctly.
  • Small-maintainer risk is real but scoped. 63 stars, zero dependents, single maintainer, terse releases. That's an acceptable trade for a low-blast-radius internal support tool. Treat it as a vendored internal dependency: pin the exact minor, review on a schedule, keep a thin wrapper around the API so a swap-out is a day's work, and don't let it grow tentacles into customer-facing code paths.
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.
adachsoft/changelog-linter
adachsoft/collection
payerurl/telegrambot-crypto-payment-instant-payout
dskripchenko/laravel-hybrid-search
riorizkyrainey/lara-ced
mehedimi/static-vel
zharp/zharp
nonsapiens/bigquery-model-sync
lgu-bayambang-ict-office/lgu-laravel-development-standards
andydefer/laravel-support
se7enxweb/flysystem
lampwick/laravel
jeslage/statamic-emojis
micahdshackelford/rmap-laravel
draftsmaninc/draftsman
square-bit/laravel-volition
himito/laravel-mailman
htinlynn/genius-helper
maco-studios/hephaestus
elmogy/larafast