Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Spark Impersonate Laravel Package

lucacri/spark-impersonate

Spark Impersonate adds secure user impersonation to Laravel Spark, letting admins log in as any user to troubleshoot issues and provide support without needing passwords. Simple to install and integrates cleanly with Spark's existing authentication.

View on GitHub
Deep Wiki
Context7

Getting Started

This is a Nova field (not an action) that renders an "Impersonate" control on a resource — in practice, your User resource — and calls Spark's built-in impersonation route so you can log in as that user and see the app through their eyes.

Prerequisites

  • Laravel app already running Laravel Spark and Laravel Nova (the package binds a Nova field, so Nova is mandatory).
  • A working Spark Kiosk/impersonation setup: Spark ships the impersonation controller and route, but it denies by default until you authorize it.

Install

composer require lucacri/spark-impersonate

Authorize impersonation in Spark (app/Providers/SparkServiceProvider.php) — without this the button will return a 403:

use Laravel\Spark\Spark;

Spark::canImpersonate(function ($user, $impersonated) {
    return $user->isAdmin(); // or role check / Gate
});

Add the field to app/Nova/User.php:

use Lucacri\SparkImpersonate\Impersonate; // verify namespace in vendor/

public function fields(Request $request)
{
    return [
        // ...
        Impersonate::make()->onlyOnDetail(),
    ];
}

Where to look first

  1. vendor/lucacri/spark-impersonate/src/ — the field class, its component(), and any withMeta() it passes to Vue. That tells you exactly which URL the button posts to.
  2. php artisan route:list | grep -i impersonat — confirm Spark's impersonation route name/path actually exists in your Spark version, since the package assumes one.
  3. Your SparkServiceProvider — confirm canImpersonate returns true for you.

First use case: open a user record in Nova → detail view → click Impersonate → the request swaps your session to that user and redirects into the Spark app. Use Spark's "stop impersonating" route (or the field's counterpart, if provided) to return to your admin session.

Implementation Patterns

Gate the field in the UI, gate the route on the server. Nova's canSee only hides the control; Spark's canImpersonate is the real enforcement. Do both:

Impersonate::make()
    ->onlyOnDetail()
    ->canSee(fn ($request) => $request->user()->isAdmin()),
// SparkServiceProvider
Spark::canImpersonate(fn ($user, $impersonated) => $user->isAdmin());

Detail-only by default. Impersonation from an index row is a footgun; keep it on the detail view where the admin can see who they're about to become.

Teams / multi-tenant apps. Spark impersonation swaps the authenticated user but does not necessarily set the correct current_team_id. If your app resolves team context from the session, set it after impersonation (e.g. in a middleware or by redirecting through a route that re-resolves the team) or the impersonated user may land in the wrong workspace.

Pair with a "stop impersonating" affordance. If the field doesn't render one automatically, add a Nova tool/action or a plain link to Spark's stop-impersonation route so admins don't have to hand-clear the session. Check withMeta() on the field to see if a stop URL is already exposed to the Vue component.

Bulk or scripted impersonation. The field is per-record. If you need the same behavior from an artisan command or a Nova Action, don't call the field — replicate what Spark's controller does: Auth::login($user), store the impersonator id in the session (session(['impersonated_by' => $admin->id])), regenerate the session, then redirect. Keep it behind the same canImpersonate check.

Testing. Don't try to unit-test the Vue control. Cover the server side:

$this->actingAs($admin)
    ->post(route('spark.kiosk.users.impersonate', $user)) // verify actual route name
    ->assertRedirect();

$this->assertAuthenticatedAs($user);
$this->assertEquals($admin->id, session('impersonated_by'));

Use withoutMiddleware(VerifyCsrfToken::class) or include the token if the POST is CSRF-protected.

Upgrade isolation. Because the field is thin, the safest pattern is to treat it as a convenience wrapper. If the package breaks on a future Nova/Spark release, replace it with a 30-line Nova Action that hits the same Spark route — same UX, one less dependency.

Gotchas and Tips

It's effectively unmaintained. Last release 2019-10-17, 11 stars. It targets the Nova 2/3 field API and an older Spark route layout. Expect breakage on Nova 4+ (the JS asset pipeline changed: no laravel-nova Vue mixin, different Nova::script/Nova::style registration) and on Spark majors that renamed the impersonation routes. Pin Nova/Spark or budget time to fork the field component.

Route names drift between Spark versions. The field hardcodes a URL to Spark's impersonation endpoint. If the button 404s, run php artisan route:list and compare against the withMeta() URL in the field class — you'll likely need to override it in a subclass.

A 403 almost always means canImpersonate is missing or false. Spark denies by default. After editing SparkServiceProvider, run php artisan config:clear — cached config is the usual culprit.

UI/authorization mismatch. If canSee returns true but canImpersonate returns false, the admin sees a button that 403s with no explanation. Keep the two checks in a shared policy/Gate method so they can't drift.

Don't impersonate yourself. You'll swap your own session into a "you impersonating you" state and the stop route may not restore cleanly. Guard against $request->user()->id === $user->id in your canImpersonate callback.

Session regeneration and CSRF. Impersonation rotates the session id. If you front it with your own route, keep the web middleware (session + CSRF) and redirect (not render) afterwards, or the new session won't persist.

Debugging checklist: browser network tab on the POST (status + Location), storage/logs/laravel.log, php artisan route:list for the target route, and Vue devtools to inspect the field's meta (it contains the URL the button will hit). If the redirect lands on Spark's home instead of your intended page, the field isn't passing a redirect target — override withMeta() in a subclass.

Extension point is the field class itself. Subclass Impersonate, override component() if you want your own button, or withMeta() to inject a stop-impersonation URL, a redirect target, or team context. That's the cleanest way to adapt the package without editing vendor/.

Alternatives worth weighing: Nova's own "log in as user" action patterns, or a purpose-built impersonation package, give you a maintained path with the same behavior. Given the low star count and stale release, treat this as glue code you may end up owning.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
socialdept/tenant-domains
tautvydasr/blade-class-names
socialdept/color-scales
maherelgamil/controller
coleus/widgets
coleus/table
coleus/users
coleus/music
coleus/health
coleus/calendar
coleus/notes
coleus/support
coleus/settings
coleus/apps
seampact/laravel
emmyconceptng/laravel-ng-postcode
jjsquady/round-robin
skyraptor/chatter
edlugz/sasapay
abbasudo/artisan-route