Impersonation
Sign in as another user to see what they see, then switch back. Impersonation is for support and debugging; for your own accounts use linked accounts.
Starting
A POST to account-switcher.impersonate with the user's key, or the facade:
use Packstub\AccountSwitcher\Facades\AccountSwitcher;
if (AccountSwitcher::canImpersonate(auth()->user(), $user)) {
AccountSwitcher::impersonate($user);
return redirect()->to(AccountSwitcher::redirectUrlFor($user));
}
impersonate() re-authenticates the session as the target, stores the impersonator in the session, writes an audit row and dispatches the events. It throws AccountSwitchDenied (an AuthorizationException, a 403 when uncaught) when not allowed; the route answers 404 for an unknown user.
Where the browser lands afterwards is redirect_to in the config, redirectTo() on the app context, or the home page. See Configuration.
Authorization
canImpersonate() is false, and impersonate() throws, unless all of these pass:
- The target is not the current user.
- The session is not already impersonating (no nesting).
- Impersonation is on (
features.impersonationin the config). canImpersonate($target)on the current user returns true, if the method exists.canBeImpersonated($by)on the target returns true, if the method exists.- The app context's
canImpersonateUsing()callback returns true, if set.
class User extends Authenticatable
{
public function canImpersonate(User $target): bool
{
return $this->hasRole('super-admin');
}
public function canBeImpersonated(User $by): bool
{
return ! $this->hasRole('super-admin');
}
}
Important
Without canImpersonate() on your model, every signed-in user can impersonate. Add it before going to production, or register a rule on the app context.
use Packstub\AccountSwitcher\AppContext;
$this->app->make(AppContext::class)
->canImpersonateUsing(fn (User $by, User $target): bool => $by->can('impersonate', $target));
The banner
<x-account-switcher::banner />
While impersonating, a fixed banner reads "You are signed in as Jane, impersonating from Admin" with a Switch back button. It renders nothing otherwise, so it can sit in the layout of every page. Names come from the name attribute, then the e-mail; userLabelUsing() on the app context changes that.
<x-account-switcher::banner position="top" style="light" />
To restyle it completely, publish the views and edit resources/views/vendor/account-switcher/components/banner.blade.php. The banner uses inline styles only, so it needs no build step and works with any CSS setup.
Landing on a hidden page
The page the browser lands on after a switch may be one the new account cannot see: a record the impersonated user has no access to, or a page that does not exist for them. Rather than show them a 403 or 404 as their first impression, give the app context a fallback; the switch flashes it and, if the landing request fails with 403 or 404, the browser is sent there instead. It applies to that one request only.
$this->app->make(AppContext::class)
->fallbackTo(fn (User $user): string => route('dashboard'));
Off until set. Inside a Filament panel the plugin turns it on by itself and sends the account to a panel it may access.
Switching back
Switch back posts to account-switcher.switch-back, a CSRF-protected route behind auth. It restores the impersonator's session, logs the end of the impersonation and returns to the page the impersonation started from.
Programmatically:
AccountSwitcher::isImpersonating(); // bool
AccountSwitcher::impersonator(); // ?Authenticatable
$url = AccountSwitcher::stopImpersonating();
If the impersonator no longer exists, the session is signed out and stopImpersonating() returns login_url from the config, the login route when there is one, or the home page.
Turning it off
// config/packstub-account-switcher.php
'features' => ['impersonation' => false],
canImpersonate() returns false and impersonate() throws AccountSwitchDenied. The routes stay registered and answer 403.
Events and log
Impersonating dispatches AccountSwitching then AccountSwitched with SwitchReason::Impersonation; switching back dispatches AccountSwitched with SwitchReason::ImpersonationEnded. Both write to the switch log. Listen to them to alert on impersonation of sensitive accounts or to invalidate API tokens.