validate([ 'email' => ['required', 'email'], 'password' => ['required', 'string'], 'device_name' => ['required', 'string', 'max:255'], 'app_version' => ['nullable', 'string', 'max:50'], ]); $user = User::where('email', $data['email'])->first(); if (! $user || ! Hash::check($data['password'], $user->password)) { throw ValidationException::withMessages([ 'email' => [__('auth.failed')], ]); } // One token per device name: revoke the previous one for this device. $user->tokens()->where('name', $data['device_name'])->delete(); $token = $user->createToken($data['device_name'], ['mobile-sync']); Device::updateOrCreate( ['user_id' => $user->id, 'name' => $data['device_name']], [ 'token_id' => $token->accessToken->id, 'app_version' => $data['app_version'] ?? null, 'last_seen_at' => now(), ] ); return response()->json([ 'token' => $token->plainTextToken, 'user' => $this->userPayload($user), ]); } public function me(Request $request) { return response()->json(['user' => $this->userPayload($request->user())]); } public function logout(Request $request) { $token = $request->user()->currentAccessToken(); // Clean up the device record bound to this token. Device::where('token_id', $token->id)->delete(); $token->delete(); return response()->json(['message' => 'Logged out']); } private function userPayload(User $user): array { return [ 'id' => $user->id, 'name' => $user->name, 'email' => $user->email, 'roles' => $user->getRoleNames(), 'permissions' => $user->getAllPermissions()->pluck('name')->values(), ]; } }