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 Impersonatable Guard Laravel Package

ukeloop/laravel-impersonatable-guard

A Laravel authentication guard for securely impersonating users. Let admins sign in as another account, switch back to the original user, and integrate impersonation with existing guards and auth flows without custom session handling.

View on GitHub
Deep Wiki
Context7

Getting Started

Install the package and publish its configuration before touching any auth code:

composer require ukeloop/laravel-impersonatable-guard
php artisan vendor:publish --tag=impersonatable-guard-config

The first place to look is config/auth.php. This package works by registering an additional guard driver, so you add a guard entry alongside your existing web guard rather than replacing it:

'guards' => [
    'web' => ['driver' => 'session', 'provider' => 'users'],

    'impersonator' => [
        'driver' => 'impersonatable',
        'provider' => 'users',
    ],
],

Then check the published config file for the keys it exposes (typically the underlying session guard to wrap, the session key used to store the impersonator's ID, and any redirect targets). Read src/ for the guard class and its public methods — the day-to-day API is almost always the trio of start impersonation, stop impersonation, and is currently impersonating.

Your first real use case: an admin users index with a "Log in as this user" button. The controller calls the impersonatable guard to authenticate as the target user while stashing the admin's own ID in the session. The admin browses the app as that user, and a "Return to my account" link restores the original session.

Verify the exact method names against the guard class before writing controllers — the guard is resolved via Auth::guard('impersonator'), so the surface is Auth::guard('impersonator')->impersonate($user) / ->stopImpersonating() style call sites in most releases of this package, but confirm in src/ for the version you install.

Implementation Patterns

Route + controller pair. Keep impersonation behind a dedicated, named route pair so you can reason about authorization in one place:

Route::post('/users/{user}/impersonate', [ImpersonationController::class, 'start'])
    ->middleware(['auth', 'can:impersonate,App\Models\User']);
Route::delete('/impersonate', [ImpersonationController::class, 'stop'])
    ->middleware('auth');

Put the authorization check in a policy or gate on the impersonator, not on the target user — the whole point is that the target user usually can't consent.

Guard-scoped resolution. Inside impersonation code always be explicit about which guard you mean. Auth::user() resolves the default guard, which is normally web, not your impersonatable guard. Prefer Auth::guard('impersonator')->user() in the controller and use Auth::guard('impersonator')->check() for the "am I impersonating?" test that drives your UI banner.

Persistent UI affordance. A global banner is non-negotiable for safety. Put it in your layout and gate it on the impersonation check, with the stop route as a form POST/DELETE so it can't be triggered by a stray link prefetch:

@if (Auth::guard('impersonator')->check())
    <div class="bg-amber-100 p-2">
        Impersonating {{ Auth::guard('impersonator')->user()->name }}
        <form method="POST" action="{{ route('impersonate.stop') }}">
            @csrf @method('DELETE')
            <button>Return to my account</button>
        </form>
    </div>
@endif

Middleware to scope the impersonated session. If you only want impersonation active on read-only screens, wrap those routes in a middleware that aborts when the impersonatable guard is active and the request is not a GET. This is cheaper than trying to bolt authorization checks onto every destructive action.

Testing. Because impersonation is session-backed, feature tests need $this->actingAs($admin) followed by a POST to the start route, then assertions through the impersonatable guard. Assert both directions: that the impersonated user is returned while active, and that the original admin is returned after stopping. Add a test that the stop route 403s when no impersonation is active.

Upgrading to v3. This major is Laravel 13 support. Bump laravel/framework to ^13.0 and php to whatever the package's composer.json requires, refresh your CI matrix (the release notes show actions/checkout and ramsey/composer-install bumps, which is a signal the test matrix moved forward), and re-run your impersonation feature tests — session key behaviour across a session-guard rewrite is the most likely place for a silent regression.

Gotchas and Tips

Nested impersonation is the classic footgun. If an admin impersonates user A and then impersonates user B, a naive session store overwrites the original admin ID and you strand the session. Guard the start route against being hit while already impersonating (abort 409 or redirect to stop first), and test it explicitly.

Remember-me tokens. If your web guard issues remember tokens, switching the session's authenticated user can leave the browser holding a remember cookie for the wrong identity. Either disable remember on impersonation routes or explicitly cycle the token on stop. This is also the reason to keep impersonation on its own guard rather than calling Auth::login($user) directly.

password.confirm and re-auth walls. Impersonated sessions often sail past confirmation middleware because the session was authenticated recently. If you have destructive admin actions gated on password.confirm, verify the impersonated user can't reach them — or you've built a privilege escalation path.

Logout hygiene. Clear the impersonation marker on logout and on session regeneration. A stale impersonator ID in a recycled session is a real vulnerability class, not a cosmetic bug.

Config cache. After editing the guard entry or the package config, run php artisan config:cache (or config:clear in dev). A stale cached auth.php is the most common reason the new guard driver "doesn't exist".

Debugging checklist. php artisan route:list --middleware to confirm your impersonation routes carry the guards you expect; php artisan about to verify the package is discovered; session()->all() dumped from a test route to inspect the impersonation keys the package writes. If the guard resolves but check() is false, the problem is nearly always that the session guard you wrapped isn't the one your routes authenticate against.

Audit trail. Impersonation without logging is an incident waiting to happen. Regardless of whether this package dispatches events, wrap the start/stop controller actions and record actor, target, timestamp, and IP to your own audit table or log channel.

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.
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
shitoudev/permissionmanager
johannesclimacus/laravel-tui
hocvt/seotools
vitalybaev/sypexgeo
amphibee/themosis-ignition
gito-me/fast-excel
frankyso/laravel-ipaymu
geolize-studio/laravel-chile
boomerangui/chat
cgv/localized-resource
noith/settings
kda/laravel-package
kda/filament-dynamic-navigation
bypersoft/signbox
pairus/product-data
fayne/laravel-filament-cms-core