Skip to content

Impersonation ​

Kinetix Impersonation lets an admin "log in as" another user to reproduce a problem or support them — safely. The users.impersonate ability controls who may impersonate, a built-in escalation guard blocks impersonating a super-admin, sensitive routes can be sealed off while impersonating, and every session is recorded through the Activity event spine.


Configuration ​

Enable it in config/kinetix.php (opt-in, default off):

php
'impersonation' => [
    'enabled'       => env('KINETIX_IMPERSONATION_ENABLED', false),
    'redirect_to'   => env('KINETIX_IMPERSONATION_REDIRECT', '/'),       // after start
    'redirect_back' => env('KINETIX_IMPERSONATION_REDIRECT_BACK', '/'),  // after leaving

    // Optional override of the escalation guard.
    // fn (Authenticatable $impersonator, Authenticatable $target): bool
    'can_impersonate' => null,
],

Each redirect can also be a callable array (not a closure: config must cache) that receives the user the session belongs to — the target after starting, the admin after leaving — and returns the URL. In an app with teams, that lands each one on their own team's pages:

php
'redirect_to'   => [App\Kinetix\ImpersonationRedirects::class, 'target'],
'redirect_back' => [App\Kinetix\ImpersonationRedirects::class, 'admin'],
php
class ImpersonationRedirects
{
    public static function target(User $user): string
    {
        return route('dashboard', ['current_team' => $user->currentTeam]);
    }

    public static function admin(User $user): string
    {
        return route('configuration.users', ['current_team' => $user->currentTeam]);
    }
}

No migration — impersonation lives entirely in the session.


1. Starting & leaving ​

Add the ImpersonateAction to your users table; it posts to the Kinetix endpoint and reloads the page as the target user:

php
use Happones\Kinetix\Actions\ImpersonateAction;

Table::make(User::query())->recordActions([
    ImpersonateAction::make(), // authorized by `users.impersonate`
]);

Mount the banner once in your authenticated layout so the admin always has a way back:

vue
<script setup lang="ts">
import KinetixImpersonationBanner from '@/components/kinetix/KinetixImpersonationBanner.vue'
</script>

<template>
  <KinetixImpersonationBanner />
  <slot />
</template>

It renders nothing unless a session is active; otherwise it shows "You are impersonating …" with a Return to your account button.

Impersonation bannerImpersonation banner

Programmatically:

php
use Happones\Kinetix\Impersonation\KinetixImpersonation;

KinetixImpersonation::start($user);
KinetixImpersonation::isImpersonating();   // true
KinetixImpersonation::stop();

2. Safety ​

This is the part that matters — impersonation done naively is a privilege-escalation hole.

  • Who can impersonate is the users.impersonate ability (registers with the permission matrix when Permissions is on). Grant it only to admins.

  • Escalation guard: you cannot impersonate a super-admin unless you are one (kinetix.permissions.super_admin_role). Tighten it further with the can_impersonate closure — e.g. restrict to users in the same team, or with a lower role rank.

  • Block sensitive actions while impersonating with the kinetix.impersonation.protect middleware. Apply it to anything that changes credentials or spends money so an admin acting as a user can't, say, change their password or buy a plan:

    php
    Route::middleware('kinetix.impersonation.protect')->group(function () {
        Route::put('/user/password', ...);
        Route::put('/user/email', ...);
        Route::post('/billing/subscribe', ...);
        Route::delete('/user', ...);  // account deletion
    });

    kinetix.impersonation.protect:writes blocks only the requests that change something (anything but GET, HEAD and OPTIONS), so the admin still sees the page they came to help with — the plan and its invoices — without acting on it. It suits a whole group, like the billing routes:

    php
    // config/kinetix.php
    'billing' => [
        'middleware' => ['web', 'auth', 'kinetix.impersonation.protect:writes'],
    ],
  • Audited: start and stop are logged through the Activity event spine (impersonate.start / impersonate.stop, causer = the admin) when the Activity module is enabled — so impersonation is never invisible.


3. Endpoints ​

Team-aware, under the Kinetix route prefix:

MethodEndpointDescription
POST{prefix}/impersonate/{user}Start (gated by users.impersonate + the escalation guard)
DELETE{prefix}/impersonateLeave (open — the impersonated user must be able to exit)

The target is resolved by id through the auth provider, so the package needs no reference to your User model. useKinetixImpersonation() exposes active, impersonatedName and leave() if you want to build your own banner.

Released under the MIT License.