validate([ 'user_id' => ['required', 'integer', 'exists:users,id'], ]); $impersonator = Auth::user(); $target = User::findOrFail((int) $request->input('user_id')); if (! $impersonator || ! method_exists($impersonator, 'tokenCan') || ! $impersonator->tokenCan('admin')) { return response()->json(['error' => 'Unauthenticated.'], 401); } if ((int) $impersonator->id === (int) $target->id) { return response()->json([ 'status' => 'failed', 'message' => 'Tidak boleh impersonate akaun sendiri.', ], 422); } if (method_exists($impersonator, 'canImpersonate') && ! $impersonator->canImpersonate()) { return response()->json([ 'status' => 'failed', 'message' => 'Akses ditolak (impersonate).', ], 403); } if (method_exists($target, 'canBeImpersonated') && ! $target->canBeImpersonated()) { return response()->json([ 'status' => 'failed', 'message' => 'Akaun ini tidak boleh di-impersonate.', ], 403); } // Revoke current token to reduce risk of dual active sessions. try { if (method_exists($impersonator, 'token') && $impersonator->token()) { $impersonator->token()->revoke(); } } catch (\Throwable $e) { // Best effort. } // Encode impersonator id in token name for later "leave" action. $tokenName = 'impersonate:' . (int) $impersonator->id; $accessToken = $target->createToken($tokenName, ['admin'])->accessToken; activity() ->performedOn($target) ->withProperties([ 'admin_id' => $impersonator->id, 'admin_name' => $impersonator->name, 'admin_email' => $impersonator->email, 'impersonated_user_id' => $target->id, 'impersonated_user_name' => $target->name, 'impersonated_user_email' => $target->email, 'ip' => $request->ip(), 'user_agent' => $request->userAgent(), ]) ->log("admin impersonate: {$impersonator->email} -> {$target->email}"); return response()->json([ 'status' => 'success', 'message' => 'Impersonate berjaya.', 'user' => $target, 'impersonator' => $impersonator, 'token' => $accessToken, ]); } }