PHPackages                             franbarbalopez/mirror - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Authentication &amp; Authorization](/categories/authentication)
4. /
5. franbarbalopez/mirror

ActiveLibrary[Authentication &amp; Authorization](/categories/authentication)

franbarbalopez/mirror
=====================

Mirror is a Laravel package that handles user impersonation.

v1.5.0(2mo ago)1548.1k↓16.1%5MITPHPPHP ^8.2CI passing

Since Nov 13Pushed 2mo ago2 watchersCompare

[ Source](https://github.com/franbarbalopez/mirror)[ Packagist](https://packagist.org/packages/franbarbalopez/mirror)[ Docs](https://github.com/franbarbalopez/mirror)[ RSS](/packages/franbarbalopez-mirror/feed)WikiDiscussions master Synced 1mo ago

READMEChangelog (6)Dependencies (16)Versions (8)Used By (0)

[![Mirror Logo](art/logo.png)](art/logo.png)

 [![Latest Version on Packagist](https://camo.githubusercontent.com/24340facb5760d0bdf787ff1c4edeb91da064d2e9564a8440856e3327612a8b4/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f6672616e62617262616c6f70657a2f6d6972726f722e737667)](https://camo.githubusercontent.com/24340facb5760d0bdf787ff1c4edeb91da064d2e9564a8440856e3327612a8b4/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f6672616e62617262616c6f70657a2f6d6972726f722e737667) [![GitHub Tests Action Status](https://camo.githubusercontent.com/785b3457730862d63a87c7e38ac2383abd73285f80c8ee6b1c6398d01b438bdd/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f616374696f6e732f776f726b666c6f772f7374617475732f6672616e62617262616c6f70657a2f6d6972726f722f74657374732e796d6c3f6c6162656c3d7465737473)](https://camo.githubusercontent.com/785b3457730862d63a87c7e38ac2383abd73285f80c8ee6b1c6398d01b438bdd/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f616374696f6e732f776f726b666c6f772f7374617475732f6672616e62617262616c6f70657a2f6d6972726f722f74657374732e796d6c3f6c6162656c3d7465737473) [![Total Downloads](https://camo.githubusercontent.com/37242d52525fdfa302c50c44c5431f7987616788a6e2c1e5529e0a104bb5ee43/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f6672616e62617262616c6f70657a2f6d6972726f722e737667)](https://camo.githubusercontent.com/37242d52525fdfa302c50c44c5431f7987616788a6e2c1e5529e0a104bb5ee43/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f6672616e62617262616c6f70657a2f6d6972726f722e737667) [![License](https://camo.githubusercontent.com/6f9a07334b44d3002bf1f255fe4e0cd296a26b71fbd10574e856308599de5fcd/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f6c2f6672616e62617262616c6f70657a2f6d6972726f722e737667)](https://camo.githubusercontent.com/6f9a07334b44d3002bf1f255fe4e0cd296a26b71fbd10574e856308599de5fcd/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f6c2f6672616e62617262616c6f70657a2f6d6972726f722e737667)

Mirror
======

[](#mirror)

Mirror is an elegant user impersonation package for Laravel. It allows administrators to seamlessly log in as other users to troubleshoot issues, provide support, or test user experiences. Mirror handles session integrity with cryptographic verification, automatic expiration, multi-guard support, flexible middleware, and lifecycle events for audit logging. Perfect for production applications that need reliable and secure user impersonation.

Features
--------

[](#features)

- HMAC-SHA256 session integrity to prevent tampering
- Configurable TTL expiration
- Middleware for access control and TTL enforcement
- Multi-guard support
- Flexible URL redirection
- Lifecycle events for audit logging

Requirements
------------

[](#requirements)

- PHP 8.2+
- Laravel 11+

Installation
------------

[](#installation)

```
composer require franbarbalopez/mirror
```

Optional - publish the config file:

```
php artisan vendor:publish --tag=mirror
```

Quick Start
-----------

[](#quick-start)

### 1. Add Trait to User Model

[](#1-add-trait-to-user-model)

```
use Illuminate\Foundation\Auth\User as Authenticatable;
use Mirror\Concerns\Impersonatable;

class User extends Authenticatable
{
    use Impersonatable;

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

    public function canBeImpersonated(): bool
    {
        return ! $this->hasRole('super-admin');
    }
}
```

**Important:** If you don't implement `canImpersonate()`, everyone can impersonate everyone. The trait returns `true` by default.

### 2. Start Impersonating

[](#2-start-impersonating)

```
use Mirror\Facades\Mirror;

public function impersonate(User $user)
{
    Mirror::start($user);

    return redirect()->route('dashboard');
}
```

### 3. Stop Impersonating

[](#3-stop-impersonating)

```
public function leave()
{
    Mirror::stop();

    return redirect()->route('admin.users.index');
}
```

Security
--------

[](#security)

Impersonation sessions are protected with HMAC-SHA256 hashes using your app key. The hash covers the impersonator ID, guard name, start time, and redirect URL. On every `stop()` call, Mirror verifies this hash - if someone's tampered with the session, it throws an exception and clears everything.

Configure TTL in `config/mirror.php` to automatically expire sessions after a set time.

API Reference
-------------

[](#api-reference)

### Starting Impersonation

[](#starting-impersonation)

By user instance:

```
Mirror::start($user);

// With redirect URLs
$redirectUrl = Mirror::start(
    user: $targetUser,
    leaveRedirectUrl: route('admin.users.index'),
    startRedirectUrl: route('dashboard')
);

return redirect($redirectUrl);
```

By primary key (works with int, UUID, ULID, etc.):

```
Mirror::startByKey(123);

Mirror::startByKey('550e8400-e29b-41d4-a716-446655440000');
```

By email:

```
Mirror::startByEmail('user@example.com');
```

### Stopping Impersonation

[](#stopping-impersonation)

```
Mirror::stop();

// Force stop - bypasses TTL check but still verifies integrity
Mirror::forceStop();
```

Use `forceStop()` when you need to end impersonation from admin actions or cleanup scripts - it skips the TTL check but still throws if the session's been tampered with.

### Checking State

[](#checking-state)

```
Mirror::isImpersonating(): bool
Mirror::getImpersonator(): ?Authenticatable
Mirror::impersonatorId(): int|string|null
Mirror::getLeaveRedirectUrl(): ?string
```

### Aliases

[](#aliases)

```
Mirror::as($user);           // same as start()
Mirror::leave();             // same as stop()
Mirror::impersonating();     // same as isImpersonating()
Mirror::impersonator();      // same as getImpersonator()
```

Middleware
----------

[](#middleware)

### `mirror.ttl`

[](#mirrorttl)

Checks if the impersonation session has expired and automatically calls `stop()` if needed:

```
Route::middleware('mirror.ttl')->group(function () {
    Route::get('/admin/users', [UserController::class, 'index']);
    Route::get('/admin/users/{user}', [UserController::class, 'show']);
});
```

Good for protecting sensitive admin areas where you want expired sessions to exit gracefully. Note that when TTL expires, this middleware will end the impersonation and redirect, so make sure your session cleanup is set up properly.

### `mirror.require`

[](#mirrorrequire)

Only allows access if actively impersonating:

```
Route::middleware('mirror.require')->group(function () {
    Route::get('/impersonation/banner', function () {
        return view('impersonation.banner');
    });
});
```

Useful for special UI components that only make sense during impersonation - like a banner showing who you're impersonating.

### `mirror.prevent`

[](#mirrorprevent)

Blocks access while impersonating:

```
Route::middleware('mirror.prevent')->group(function () {
    Route::post('/admin/users/{user}/delete', [UserController::class, 'destroy']);
    Route::get('/admin/settings', [SettingsController::class, 'edit']);
});
```

Protects destructive actions or sensitive settings that should only be accessed as the original user, not while impersonating someone else.

Authorization
-------------

[](#authorization)

The `Impersonatable` trait provides two methods that both return `true` by default. Override them to add your own logic:

```
use Mirror\Concerns\Impersonatable;

class User extends Authenticatable
{
    use Impersonatable;

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

    public function canBeImpersonated(): bool
    {
        return ! $this->hasRole('super-admin');
    }
}
```

You don't need the trait - Mirror will look for these methods on your user model regardless:

```
class User extends Authenticatable
{
    public function canImpersonate(): bool
    {
        return $this->hasPermission('impersonate-users');
    }

    public function canBeImpersonated(): bool
    {
        return ! $this->is_system_account;
    }
}
```

URL Redirection
---------------

[](#url-redirection)

You can control where users go when starting and stopping impersonation:

```
public function impersonate(User $user)
{
    $redirectUrl = Mirror::start(
        user: $user,
        leaveRedirectUrl: route('admin.users.index'),  // where to go when they stop
        startRedirectUrl: route('dashboard')            // where to go right now
    );

    return redirect($redirectUrl);
}

public function leave()
{
    Mirror::stop();

    return redirect(Mirror::getLeaveRedirectUrl());
}
```

If you don't specify `leaveRedirectUrl`, it defaults to the current URL where `start()` was called.

Events
------

[](#events)

Mirror dispatches two events you can listen to:

- `Mirror\Events\ImpersonationStarted`
- `Mirror\Events\ImpersonationStopped`

Both events contain the impersonator, the target user, and the guard name. Good for audit logs or triggering workflows.

Events are dispatched **after the response** is sent to the client, ensuring that critical impersonation operations complete without delay. This is especially important for middleware like `mirror.ttl` that may run on every request.

```
use Mirror\Events\ImpersonationStarted;

Event::listen(ImpersonationStarted::class, function (ImpersonationStarted $event) {
    // Log the activity to your audit system of choice
    Log::info('User impersonation started', [
        'impersonator_id' => $event->impersonator->id,
        'impersonated_id' => $event->impersonated->id,
        'guard' => $event->guardName,
    ]);
});
```

Performance &amp; Optimization
------------------------------

[](#performance--optimization)

Mirror is optimized for high-performance applications:

### Request-Scoped Caching

[](#request-scoped-caching)

The impersonator model is cached within a single request to avoid redundant database queries:

```
// This first call will query the database
$impersonator = Mirror::getImpersonator();

// Subsequent calls in the same request use the cached instance, therefore this one will not:
$impersonator = Mirror::getImpersonator();
```

This is particularly beneficial for middleware like `mirror.ttl` that run on every request.

### Deferred Event Dispatching

[](#deferred-event-dispatching)

Impersonation events are dispatched after the response is sent to the client, ensuring that event listeners don't impact response time. This keeps your request cycle fast while still allowing audit logging and other background tasks.

Multi-Guard Support
-------------------

[](#multi-guard-support)

Mirror automatically detects which guard you're using:

```
Auth::guard('admin')->login($admin);

Mirror::start($user); // uses 'admin' guard

Mirror::stop(); // restores to 'admin' guard
```

You don't need to specify the guard manually - it figures it out from the current auth context.

Blade Directives
----------------

[](#blade-directives)

**@impersonating**

```
@impersonating

        You're impersonating {{ auth()->user()->name }}.
        Exit

@endimpersonating

{{-- Check specific guard --}}
@impersonating('admin')
    Impersonating via admin guard
@endimpersonating
```

**@canImpersonate**

```
@canImpersonate
    Manage Users
@endcanImpersonate

{{-- With guard --}}
@canImpersonate('admin')
    Admin tools
@endcanImpersonate
```

**@canBeImpersonated**

```
{{-- Check current user --}}
@canBeImpersonated
    Available for support
@endcanBeImpersonated

{{-- Check specific user --}}
@canBeImpersonated($user)

        @csrf
        Impersonate

@endcanBeImpersonated

{{-- With guard --}}
@canBeImpersonated($user, 'admin')
    Login as this user
@endcanBeImpersonated
```

License
-------

[](#license)

MIT. See [LICENSE.md](LICENSE.md).

Credits
-------

[](#credits)

Developed by [franbarbalopez](https://github.com/franbarbalopez).

###  Health Score

52

—

FairBetter than 96% of packages

Maintenance87

Actively maintained with recent releases

Popularity42

Moderate usage in the ecosystem

Community14

Small or concentrated contributor base

Maturity52

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 83.3% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~24 days

Recently: every ~29 days

Total

6

Last Release

65d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/5fac6595ce2d805f6e5a18e77e4b66fc8da6435ac13ca4870c5e7ed874fc4c15?d=identicon)[franbarbalopez](/maintainers/franbarbalopez)

---

Top Contributors

[![franbarbalopez](https://avatars.githubusercontent.com/u/57897024?v=4)](https://github.com/franbarbalopez "franbarbalopez (10 commits)")[![j3j5](https://avatars.githubusercontent.com/u/1239921?v=4)](https://github.com/j3j5 "j3j5 (1 commits)")[![rjp2525](https://avatars.githubusercontent.com/u/1334865?v=4)](https://github.com/rjp2525 "rjp2525 (1 commits)")

---

Tags

impersonateimpersonationlaravellaravel-packagephplaravelimpersonationimpersonate

###  Code Quality

TestsPest

Static AnalysisPHPStan, Rector

Code StyleLaravel Pint

### Embed Badge

![Health badge](/badges/franbarbalopez-mirror/health.svg)

```
[![Health](https://phpackages.com/badges/franbarbalopez-mirror/health.svg)](https://phpackages.com/packages/franbarbalopez-mirror)
```

###  Alternatives

[lab404/laravel-impersonate

Laravel Impersonate is a plugin that allows to you to authenticate as your users.

2.3k16.4M48](/packages/lab404-laravel-impersonate)[bezhansalleh/filament-shield

Filament support for `spatie/laravel-permission`.

2.8k2.9M88](/packages/bezhansalleh-filament-shield)[olssonm/l5-very-basic-auth

Laravel stateless HTTP basic auth without the need for a database

1662.5M1](/packages/olssonm-l5-very-basic-auth)[rickycezar/laravel-jwt-impersonate

Laravel Impersonate is a plugin that allows to you to authenticate as your users.

24117.6k](/packages/rickycezar-laravel-jwt-impersonate)[scaler-tech/laravel-saml2

SAML2 Service Provider integration for Laravel applications, based on OneLogin toolkit

2737.5k](/packages/scaler-tech-laravel-saml2)[hapidjus/laravel-impersonate-ui

UI for 404labfr/laravel-impersonate

371.5k](/packages/hapidjus-laravel-impersonate-ui)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
