A feature-rich user impersonation package for Laravel.
Laravel Masquerade lets trusted administrators, support agents, and staff safely sign in as another user while preserving the original account, enforcing permission checks, blocking sensitive actions, limiting impersonation duration, and recording a full audit trail.
use EloquentWorks\Masquerade\Facades\Masquerade;
Masquerade::start(
target: $user,
reason: 'Troubleshooting support ticket #1042',
metadata: [
'ticket_id' => 1042,
],
);
Masquerade::isMasquerading();
Masquerade::stop();- Secure session-backed user impersonation
- Original user restoration after masquerade sessions
- Configurable auth guard support
- Configurable user model for built-in routes
- Optional built-in start and stop routes
- Controller-driven impersonation flow
- Model-level permission methods
- Protection against nested impersonation
- Protection against impersonating yourself
- Optional required reason before starting a session
- Session ID regeneration when starting and stopping
- Configurable max session duration
- Automatic expiration middleware
- Sensitive-route blocking middleware
- Middleware for routes that require an active masquerade session
- Full audit logging with actor and target morph relationships
- Reason, IP address, user agent, metadata, start time, and end time logging
- Start, stop, denied, and expired events
- Blade conditional directive and banner directive
- Publishable banner view
- Facade and global helper
- Install and log pruning Artisan commands
- Configurable table name, messages, redirects, and routes
- Laravel Pint, PHPStan/Larastan, PHPUnit, Testbench, and GitHub Actions setup
| Laravel | PHP | Orchestra Testbench |
|---|---|---|
| 11.15+ | 8.2+ | 9.x |
| 12.x | 8.2+ | 10.x |
| 13.x | 8.3+ | 11.x |
composer require eloquent-works/masquerade
php artisan masquerade:install
php artisan migrateThe install command publishes the configuration file, migration, and banner view.
Publish only the configuration file:
php artisan vendor:publish --tag=masquerade-configPublish only the migration:
php artisan vendor:publish --tag=masquerade-migrationsPublish only the banner view:
php artisan vendor:publish --tag=masquerade-viewsForce republishing package assets:
php artisan masquerade:install --forceAdd HasMasquerade to the account model that can perform or receive impersonation.
<?php
namespace App\Models;
use EloquentWorks\Masquerade\Traits\HasMasquerade;
use Illuminate\Contracts\Auth\Authenticatable;
use Illuminate\Foundation\Auth\User as AuthenticatableUser;
class User extends AuthenticatableUser
{
use HasMasquerade;
public function canMasquerade(Authenticatable $target): bool
{
return $this->is_admin && ! $this->is($target);
}
public function canBeMasqueradedBy(Authenticatable $impersonator): bool
{
return ! $this->is_owner;
}
}By default, canMasquerade() returns false. This means nobody can masquerade until your application explicitly allows it.
use EloquentWorks\Masquerade\Facades\Masquerade;
Masquerade::start(
target: $user,
reason: 'Troubleshooting checkout issue',
metadata: [
'ticket_id' => 1042,
'source' => 'support-panel',
],
);You may also provide a specific impersonator and guard:
Masquerade::start(
target: $user,
impersonator: $admin,
guard: 'web',
reason: 'QA verification',
);Masquerade::stop();When stopped, Masquerade logs the original user back in and clears the masquerade session state.
Block sensitive actions while masquerading:
use Illuminate\Support\Facades\Route;
Route::post('/billing/payment-method', UpdatePaymentMethodController::class)
->middleware(['auth', 'masquerade.block']);Enforce automatic expiration on normal authenticated routes:
Route::middleware(['web', 'auth', 'masquerade.duration'])->group(function (): void {
Route::get('/dashboard', DashboardController::class);
});Require an active masquerade session:
Route::get('/support/masquerade-toolbar', SupportToolbarController::class)
->middleware(['auth', 'masquerade.required']);When routes are enabled, Masquerade registers:
POST /masquerade/{user}/start
POST /masquerade/stop
Start from a Blade form:
<form method="POST" action="{{ route('masquerade.start', $user) }}">
@csrf
<input
type="hidden"
name="reason"
value="Support ticket #1042"
>
<input
type="hidden"
name="redirect_to"
value="{{ route('dashboard') }}"
>
<button type="submit">
Masquerade as {{ $user->name }}
</button>
</form>Stop from a Blade form:
<form method="POST" action="{{ route('masquerade.stop') }}">
@csrf
<button type="submit">
Return to my account
</button>
</form>Disable built-in routes if you want to provide your own controller flow:
'routes' => [
'enabled' => false,
],Masquerade checks both sides of the impersonation request.
public function canMasquerade(Authenticatable $target): bool
{
return $this->hasRole('support') && ! $this->is($target);
}
public function canBeMasqueradedBy(Authenticatable $impersonator): bool
{
return ! $this->hasRole('owner');
}You may disable model permission methods in the config if your application handles authorization elsewhere:
'permissions' => [
'use_model_methods' => false,
],Every started, ended, and expired masquerade session can be recorded in masquerade_logs.
use EloquentWorks\Masquerade\Models\MasqueradeLog;
$logs = MasqueradeLog::query()
->latest()
->get();Each log may include:
- Masquerade UUID
- Action:
started,ended, orexpired - Guard name
- Impersonator morph type and ID
- Target morph type and ID
- Reason
- IP address
- User agent
- Metadata
- Started timestamp
- Ended timestamp
Access the actor and target models:
$log->impersonator;
$log->target;Use masquerade.block on routes that should never be available while impersonating another account.
Good examples include:
- Billing changes
- Password changes
- Two-factor authentication changes
- Email address changes
- API token creation
- Account deletion
- Admin permission changes
Route::middleware(['auth', 'masquerade.block'])->group(function (): void {
Route::post('/password', UpdatePasswordController::class);
Route::post('/two-factor-authentication', EnableTwoFactorController::class);
Route::delete('/account', DeleteAccountController::class);
});Show UI only while masquerading:
@masquerading
<div class="alert alert-warning">
You are currently masquerading as another user.
</div>
@endmasqueradingRender the included banner:
@masqueradeBannerOr include the published view manually:
@include('masquerade::banner')Masquerade dispatches events you can listen for:
EloquentWorks\Masquerade\Events\MasqueradeStarted::class;
EloquentWorks\Masquerade\Events\MasqueradeEnded::class;
EloquentWorks\Masquerade\Events\MasqueradeDenied::class;
EloquentWorks\Masquerade\Events\MasqueradeExpired::class;Example listener registration:
use EloquentWorks\Masquerade\Events\MasqueradeStarted;
use Illuminate\Support\Facades\Event;
Event::listen(MasqueradeStarted::class, function (MasqueradeStarted $event): void {
logger()->info('Masquerade started.', [
'uuid' => $event->uuid,
'guard' => $event->guard,
]);
});php artisan masquerade:install
php artisan masquerade:pruneExamples:
php artisan masquerade:install --force
php artisan masquerade:prune --days=90A simple feature test might look like this:
use App\Models\User;
use EloquentWorks\Masquerade\Facades\Masquerade;
use Illuminate\Support\Facades\Auth;
it('allows support admins to masquerade as users', function (): void {
$admin = User::factory()->create([
'is_admin' => true,
]);
$user = User::factory()->create();
Auth::login($admin);
Masquerade::start($user, reason: 'Support ticket');
expect(Masquerade::isMasquerading())->toBeTrue();
expect(Auth::user()->is($user))->toBeTrue();
Masquerade::stop();
expect(Auth::user()->is($admin))->toBeTrue();
});Full documentation is available in the docs directory:
- Installation
- Configuration
- Architecture
- Masquerading
- Permissions
- Routes
- Middleware
- Audit Logs
- Views and Blade
- Events
- Commands and Scheduling
- Customization
- Security
- Testing
composer validate --strict
composer qualityOr run the tools separately:
composer format
composer analyse
composer testOnly allow highly trusted users to masquerade. Always require authorization before starting a session, consider requiring a reason, and block sensitive account, billing, authentication, and destructive routes with masquerade.block.
Masquerade regenerates the session ID when starting and stopping by default. Keep that enabled unless your application has a specific reason to disable it.
Security vulnerabilities should be reported privately according to SECURITY.md.
See CONTRIBUTING.md and CODE_OF_CONDUCT.md.
Laravel Masquerade is open-source software licensed under the MIT License.