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.

v2.0.1(3d ago)16326.7k—1.8%5MITPHPPHP ^8.2CI passing

Since Nov 13Pushed 6d 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 2.x Synced 3d ago

READMEChangelog (7)Dependencies (24)Versions (12)Used By (0)

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

[](#mirror)

**Secure, elegant user impersonation for Laravel applications.**

[![Latest Version on Packagist](https://camo.githubusercontent.com/ad37ca627fb128c897d9b2a3e0d0a349cd0577f7208294ec7ed4fa9078a86625/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f6672616e62617262616c6f70657a2f6d6972726f722e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/franbarbalopez/mirror)[![Tests](https://camo.githubusercontent.com/38be4e7a0e6afa6c603fc772f312c0a45bd6b56ec902b99f5c373b1df771b1a6/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f616374696f6e732f776f726b666c6f772f7374617475732f6672616e62617262616c6f70657a2f6d6972726f722f74657374732e796d6c3f6272616e63683d6d6173746572266c6162656c3d7465737473267374796c653d666c61742d737175617265)](https://github.com/franbarbalopez/mirror/actions/workflows/tests.yml)[![PHP](https://camo.githubusercontent.com/389e283826ab98c1b1c4894fcb010ab1fd68fa9d4b2fa2f6d47dde6fd3fade9b/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f646570656e64656e63792d762f6672616e62617262616c6f70657a2f6d6972726f722f7068703f7374796c653d666c61742d737175617265)](composer.json)[![Laravel Compatibility](https://camo.githubusercontent.com/dada49eb03251c2a5429596bee39e36ac002eae040b50d1e6eaa6496a711e2b4/68747470733a2f2f62616467652e6c61726176656c2e636c6f75642f62616467652f6672616e62617262616c6f70657a2f6d6972726f72)](https://packagist.org/packages/franbarbalopez/mirror)[![Laravel Boost](https://camo.githubusercontent.com/9bdec9dbce27067f5c86de8d8442d0e3509913eee7ed50033ce9f29912091f48/68747470733a2f2f62616467652e6c61726176656c2e636c6f75642f626f6f73742d62616467652e737667)](https://github.com/laravel/boost)[![Downloads](https://camo.githubusercontent.com/2b6fe060f6da29b27e3ec11d69adf1787280a39850a5b895c74396063c33818d/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f6672616e62617262616c6f70657a2f6d6972726f722e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/franbarbalopez/mirror)

[Features](#features) | [Installation](#installation) | [Quick Start](#quick-start) | [Usage](#usage) | [Configuration](#configuration) | [Security](#security) | [Exceptions](#exceptions) | [Development](#development)

Mirror is a Laravel package for safely logging in as another user. It is designed for admin panels, support tooling, QA workflows, and production applications that need impersonation without handing route handling, redirects, or authorization policy decisions to a package.

Mirror stores a signed impersonation payload in the session, restores the original user when leaving, supports multiple session guards, exposes lifecycle events for audit logs, and keeps the application in control of the HTTP flow.

Important

Mirror only works with Laravel guards backed by the `session` driver. Token, API, and stateless guards are intentionally rejected.

Features
--------

[](#features)

- **Signed session state**: HMAC-SHA256 verification using your Laravel `app.key`.
- **Multi-guard support**: resolve the authenticated impersonator guard and infer or explicitly set the target guard.
- **Explicit authorization hooks**: require models to decide who can impersonate and who can be impersonated.
- **Custom context**: attach signed metadata such as support reasons, ticket IDs, or workflow sources.
- **TTL checks**: detect expired impersonation sessions while letting your app decide the response.
- **Blade directives**: render UI based on active impersonation and model capabilities.
- **Lifecycle events**: audit `ImpersonationStarted` and `ImpersonationStopped` events.

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

[](#requirements)

- PHP `8.2` or higher
- Laravel `11`, `12`, or `13`

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

[](#installation)

Install the package with Composer:

```
composer require franbarbalopez/mirror
```

Laravel auto-discovers the service provider and facade alias. If you want to customize the TTL or session namespace, publish the configuration file:

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

The published file is available at `config/mirror.php`.

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

[](#quick-start)

### 1. Implement the Contract

[](#1-implement-the-contract)

Every model that can start or receive impersonation must implement `Mirror\Contracts\Impersonatable`.

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

class User extends Authenticatable implements Impersonatable
{
    public function canImpersonate(): bool
    {
        return $this->hasRole('admin');
    }

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

Note

Mirror does not prescribe your authorization model. Use roles, policies, permissions, feature flags, or any business rule that fits your application.

### 2. Start Impersonating

[](#2-start-impersonating)

```
use App\Models\User;
use Mirror\Facades\Mirror;

public function impersonate(User $user)
{
    Mirror::impersonate(
        target: $user,
        context: [
            'reason' => request('reason'),
            'ticket_id' => request('ticket_id'),
        ],
    );

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

### 3. Leave Impersonation

[](#3-leave-impersonation)

```
use Mirror\Facades\Mirror;

public function leave()
{
    $context = Mirror::leave();

    audit('Impersonation ended', $context);

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

Usage
-----

[](#usage)

### Starting Impersonation

[](#starting-impersonation)

Use the facade to impersonate a target user. Mirror resolves the current authenticated session guard as the impersonator guard.

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

Pass a guard when the target user should be authenticated through a specific guard:

```
Mirror::impersonate($user, guard: 'web');
```

Attach signed context when you want to carry audit metadata across the impersonation lifecycle:

```
Mirror::impersonate(
    target: $user,
    guard: 'web',
    context: [
        'reason' => 'Support request',
        'ticket_id' => 123,
        'source' => 'admin-panel',
    ],
);
```

Mirror prevents nested impersonation and throws `ImpersonationAlreadyActive` if the current session is already impersonating another user.

### Guard Resolution

[](#guard-resolution)

Mirror resolves guards in this order:

GuardResolutionImpersonator guardFirst authenticated Laravel guard using the `session` driver.Target guardExplicit `guard` argument, when provided.Target guardTarget model `guardName()` method, `guard_name` attribute, or `guard_name` default property.Target guardFirst matching `session` guard whose provider model matches the target model.If multiple target guards match the same model, Mirror uses the first matching guard. Pass `guard:` explicitly when the choice matters.

### Reading State

[](#reading-state)

```
Mirror::active();       // bool
Mirror::expired();      // bool
Mirror::impersonator(); // ?Authenticatable
Mirror::impersonated(); // ?Authenticatable
Mirror::context();      // array
```

Use these methods to drive banners, route middleware, audit logs, or support tooling.

```
if (Mirror::active()) {
    $impersonator = Mirror::impersonator();
    $impersonated = Mirror::impersonated();
}
```

### Expiration

[](#expiration)

The `mirror.ttl` value controls whether `Mirror::expired()` returns `true`. The default is `1800` seconds.

```
if (Mirror::active() && Mirror::expired()) {
    $context = Mirror::leave();

    return redirect()
        ->route('admin.users.index')
        ->with('warning', __('Impersonation expired.'));
}
```

Tip

Mirror reports expiration, but does not force logout, redirect, or abort a request. Put your preferred behavior in middleware or controller code.

Set the TTL to `null` to disable expiration checks:

```
'ttl' => null,
```

### Blade Directives

[](#blade-directives)

Mirror registers Blade condition directives for common UI checks.

```
@impersonating

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

@endimpersonating

@notImpersonating
    Normal session
@endnotImpersonating
```

Guard-specific checks are supported:

```
@impersonating('web')
    Impersonating through the web guard
@endimpersonating
```

Capability directives call the `Impersonatable` contract methods:

```
@canImpersonate
    Manage users
@endcanImpersonate

@canBeImpersonated($user)

        @csrf
        Impersonate

@endcanBeImpersonated
```

### Events

[](#events)

Mirror dispatches two events:

EventWhen`Mirror\Events\ImpersonationStarted`After the target user is logged in.`Mirror\Events\ImpersonationStopped`After the original impersonator is restored.Both events expose `$impersonator`, `$impersonated`, and `$context`.

```
use Illuminate\Support\Facades\Event;
use Illuminate\Support\Facades\Log;
use Mirror\Events\ImpersonationStarted;

Event::listen(ImpersonationStarted::class, function (ImpersonationStarted $event): void {
    Log::info('User impersonation started', [
        'impersonator_id' => $event->impersonator->getAuthIdentifier(),
        'impersonated_id' => $event->impersonated->getAuthIdentifier(),
        'context' => $event->context,
    ]);
});
```

Configuration
-------------

[](#configuration)

The default configuration is intentionally small:

```
return [
    'ttl' => 1800,

    'session' => [
        'key' => env('MIRROR_SESSION_KEY', 'mirror.impersonation'),
    ],
];
```

OptionDefaultDescription`ttl``1800`Maximum age, in seconds, used by `Mirror::expired()`. Set to `null` to disable expiration checks.`session.key``mirror.impersonation`Session namespace used to store the signed payload and signature.Security
--------

[](#security)

Mirror stores the impersonator ID, impersonator guard, target ID, target guard, start timestamp, and context in the session. That payload is signed with HMAC-SHA256 using `config('app.key')`.

When Mirror reads impersonation state, it verifies the signature. If the payload or signature is missing or tampered with, Mirror clears the stored impersonation state and throws an exception.

Security behavior to be aware of:

- Both users must implement `Impersonatable`.
- The impersonator must return `true` from `canImpersonate()`.
- The target must return `true` from `canBeImpersonated()`.
- Only session-backed guards are accepted.
- Nested impersonation is rejected.
- Expiration is reported by `Mirror::expired()`; your application decides how to enforce it.

Warning

Keep your Laravel `APP_KEY` private and stable. Rotating it invalidates existing Mirror signatures, which is normally desirable for security but can interrupt active impersonation sessions.

Exceptions
----------

[](#exceptions)

All package exceptions extend `Mirror\Exceptions\MirrorException`. For application code, the phase interfaces are usually the best catch points.

```
use Mirror\Exceptions\CannotLeaveImpersonation;
use Mirror\Exceptions\CannotStartImpersonation;
use Mirror\Facades\Mirror;

try {
    Mirror::impersonate($user);
} catch (CannotStartImpersonation $exception) {
    report($exception);
}

try {
    Mirror::leave();
} catch (CannotLeaveImpersonation $exception) {
    report($exception);
}
```

Phase interfaceRaised byTypical cause`CannotStartImpersonation``impersonate()`Authorization failed, no authenticated session guard exists, target guard cannot be inferred, or impersonation is already active.`CannotLeaveImpersonation``leave()`No active impersonation exists or stored state is invalid.`CannotReadImpersonationState``active()`, `expired()`, `impersonator()`, `impersonated()`, `context()`Stored impersonation state cannot be trusted.Common concrete exceptions include `CanNotImpersonate`, `CanNotBeImpersonated`, `CannotInferTargetGuard`, `GuardDoesNotUseSessionDriver`, `ImpersonationAlreadyActive`, `ImpersonationNotActive`, `InvalidImpersonationSignature`, `MissingAuthenticatedSessionGuard`, and `MissingImpersonationSignature`.

Development
-----------

[](#development)

Install dependencies:

```
composer install
```

Run the full quality suite:

```
composer test
```

Useful scripts:

CommandDescription`composer test:lint`Check formatting with Laravel Pint.`composer lint`Fix formatting with Laravel Pint.`composer test:analyse`Run PHPStan/Larastan.`composer test:refactor`Run Rector in dry-run mode.`composer test:coverage`Run Pest with exactly 100% coverage.`composer fix`Run Rector and Pint fixes.`composer serve`Build and serve the Orchestra Testbench workbench app.The test suite uses [Pest](https://pestphp.com/) and [Orchestra Testbench](https://packages.tools/testbench) to validate Mirror inside a Laravel application context.

###  Health Score

57

—

FairBetter than 98% of packages

Maintenance99

Actively maintained with recent releases

Popularity45

Moderate usage in the ecosystem

Community14

Small or concentrated contributor base

Maturity54

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 85.7% 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 ~25 days

Total

10

Last Release

3d ago

Major Versions

v1.5.0 → v2.02026-06-28

1.x-dev → 2.x-dev2026-06-30

### 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 (12 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.3k18.6M64](/packages/lab404-laravel-impersonate)[directorytree/ldaprecord-laravel

LDAP Authentication &amp; Management for Laravel.

5752.3M18](/packages/directorytree-ldaprecord-laravel)[hasinhayder/tyro

Tyro - The ultimate Authentication, Authorization, and Role &amp; Privilege Management solution for Laravel 12 &amp; 13

6804.7k6](/packages/hasinhayder-tyro)[rickycezar/laravel-jwt-impersonate

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

25125.2k](/packages/rickycezar-laravel-jwt-impersonate)[masterix21/laravel-licensing

Laravel licensing package with polymorphic assignment to any model, activation keys, expirations/renewals, and seat control via LicenseUsage. Supports offline verification with public-key–signed tokens, a CLI to generate/rotate/revoke keys, and an extensible architecture via config and contracts.

1563.1k4](/packages/masterix21-laravel-licensing)[hapidjus/laravel-impersonate-ui

UI for 404labfr/laravel-impersonate

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

PHPackages © 2026

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