rickycezar/laravel-jwt-impersonate
Installation:
composer require rickycezar/laravel-jwt-impersonate
Publish the config file:
php artisan vendor:publish --provider="Rickycezar\LaravelJwtImpersonate\ServiceProvider" --tag="config"
Configuration:
Update config/laravel-jwt-impersonate.php to define:
guard_name (default: api)middleware (e.g., auth:api)impersonate_route (e.g., impersonate.user)impersonate_middleware (e.g., can:impersonate-users)First Use Case:
Add a route to trigger impersonation (e.g., in routes/api.php):
Route::post('/impersonate/{user}', [ImpersonateController::class, 'impersonate'])->name('impersonate.user');
Create a controller to handle impersonation logic:
use Rickycezar\LaravelJwtImpersonate\Facades\Impersonate;
public function impersonate(User $user)
{
return Impersonate::impersonate($user);
}
Testing: Use Postman or Laravel's HTTP tests to send a request with the target user's ID and your admin credentials:
$response = $this->actingAs($admin)
->postJson('/impersonate/' . $targetUser->id);
Impersonation Flow:
/impersonate/{user} with their JWT.can:impersonate-users).{ "token": "new.jwt.token" }).Reverting Impersonation:
Use the revert() method to switch back to the original user:
public function revert()
{
return Impersonate::revert();
}
Add a route:
Route::post('/revert', [ImpersonateController::class, 'revert'])->name('revert.impersonate');
Conditional Impersonation: Extend the package to add logic (e.g., log impersonation events or restrict by user roles):
public function impersonate(User $user)
{
if ($user->isRestricted()) {
abort(403, 'Cannot impersonate restricted users.');
}
event(new UserImpersonated($user));
return Impersonate::impersonate($user);
}
JWT Middleware:
Ensure your auth:api middleware uses the jwt.auth middleware from tyrimys/jwt-auth (or equivalent) for seamless token replacement.
Frontend Handling:
API Versioning:
If using API versioning (e.g., v1), prefix routes:
Route::prefix('v1')->group(function () {
Route::post('/impersonate/{user}', [...]);
});
Rate Limiting:
Protect impersonation routes with Laravel's throttle middleware to prevent abuse:
Route::middleware(['throttle:60,1'])->post('/impersonate/{user}', [...]);
Token Replacement:
Middleware Conflicts:
auth:api middleware runs before impersonate middleware, the original user's token may still be validated. Order matters:
// routes/api.php
Route::middleware(['auth:api', 'can:impersonate-users'])->post('/impersonate/{user}', [...]);
CSRF Protection:
$except in VerifyCsrfToken):
protected $except = [
'impersonate/*',
];
User Model Requirements:
Token Not Updating:
impersonate method is called correctly.auth:api running too early).\Log::info('Original user:', auth()->user());
$response = Impersonate::impersonate($user);
\Log::info('New user:', auth()->user());
Permission Denied:
impersonate-users ability (or your custom gate). Test with:
$this->actingAs($admin)
->postJson('/impersonate/' . $user->id)
->assertStatus(403); // Expected if no permission
Route Not Found:
impersonate_route). Use php artisan route:list to debug.Custom Claims:
Add custom claims to the impersonated JWT by extending the Impersonate facade:
use Rickycezar\LaravelJwtImpersonate\Facades\Impersonate;
public function impersonate(User $user)
{
$token = Impersonate::impersonate($user);
$token->setCustomClaim('is_impersonating', true);
return $token;
}
Event Listeners: Listen for impersonation events to log activity or notify users:
// EventServiceProvider
protected $listen = [
\Rickycezar\LaravelJwtImpersonate\Events\UserImpersonated::class => [
\App\Listeners\LogImpersonation::class,
],
];
GUI Integration: Add a button in your admin panel using Laravel Blade:
@can('impersonate-users')
<button onclick="impersonateUser({{ $user->id }})">Impersonate</button>
@endcan
JavaScript:
function impersonateUser(userId) {
axios.post(`/impersonate/${userId}`)
.then(response => {
localStorage.setItem('auth_token', response.data.token);
window.location.reload();
});
}
Multi-Guard Support:
Extend the package to support multiple auth guards by modifying the ServiceProvider:
// app/Providers/AuthServiceProvider
public function boot()
{
$this->registerPolicies();
Impersonate::extend('sanctum', function ($user) {
// Custom logic for Sanctum impersonation
});
}
How can I help you explore Laravel packages today?