eloquent-works / masquerade
A feature-rich Laravel impersonation package with secure session handling, audit logs, middleware, events, and Blade helpers.
Requires
- php: ^8.2
- illuminate/auth: ^11.15|^12.0|^13.0
- illuminate/contracts: ^11.15|^12.0|^13.0
- illuminate/database: ^11.15|^12.0|^13.0
- illuminate/encryption: ^11.15|^12.0|^13.0
- illuminate/http: ^11.15|^12.0|^13.0
- illuminate/routing: ^11.15|^12.0|^13.0
- illuminate/support: ^11.15|^12.0|^13.0
Requires (Dev)
- larastan/larastan: ^3.10
- laravel/pint: ^1.18
- orchestra/testbench: ^9.0|^10.0|^11.0
- phpunit/phpunit: ^11.0
This package is not auto-updated.
Last update: 2026-07-20 00:37:07 UTC
README
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();
โจ Highlights
- 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
๐ Requirements
| Laravel | PHP | Orchestra Testbench |
|---|---|---|
| 11.15+ | 8.2+ | 9.x |
| 12.x | 8.2+ | 10.x |
| 13.x | 8.3+ | 11.x |
๐ฆ Installation
composer require eloquent-works/masquerade php artisan masquerade:install php artisan migrate
The install command publishes the configuration file, migration, and banner view.
Publish only the configuration file:
php artisan vendor:publish --tag=masquerade-config
Publish only the migration:
php artisan vendor:publish --tag=masquerade-migrations
Publish only the banner view:
php artisan vendor:publish --tag=masquerade-views
Force republishing package assets:
php artisan masquerade:install --force
๐ค Prepare Your User Model
Add 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.
๐ญ Start Masquerading
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', );
๐ Stop Masquerading
Masquerade::stop();
When stopped, Masquerade logs the original user back in and clears the masquerade session state.
๐ก๏ธ Protect Routes
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']);
๐งญ Built-In Routes
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, ],
๐ชช Permissions
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, ],
๐งพ Audit Logs
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;
๐ซ Sensitive Route Blocking
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); });
๐งฉ Blade Directives
Show UI only while masquerading:
@masquerading <div class="alert alert-warning"> You are currently masquerading as another user. </div> @endmasquerading
Render the included banner:
@masqueradeBanner
Or include the published view manually:
@include('masquerade::banner')
๐ก Events
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, ]); });
๐งฐ Commands
php artisan masquerade:install php artisan masquerade:prune
Examples:
php artisan masquerade:install --force php artisan masquerade:prune --days=90
๐งช Testing Your App Integration
A 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(); });
๐ Documentation
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
โ Quality Checks
composer validate --strict composer quality
Or run the tools separately:
composer format
composer analyse
composer test
๐ Security
Only 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.
๐ค Contributing
See CONTRIBUTING.md and CODE_OF_CONDUCT.md.
๐ License
Laravel Masquerade is open-source software licensed under the MIT License.