all(), [ 'email' => ['required', 'email'], 'password' => ['required', 'string'], ]); if ($validator->fails()) { return $this->respondValidationError($validator->errors()->toArray()); } $email = (string) $request->input('email'); $password = (string) $request->input('password'); $user = User::query()->where('email', $email)->first(); if (!$user || !ci_password_verify($password, (string) $user->password)) { return $this->respondError('Invalid credentials.', 401); } if ((int) ($user->is_verified ?? 0) !== 1) { return $this->respondError('Account not verified.', 403); } if (strcasecmp((string) ($user->status ?? ''), 'Active') !== 0) { return $this->respondError('Account is inactive.', 403); } $jwtToken = JWTAuth::fromUser($user); $sanctumToken = $user->createToken('api')->plainTextToken; $roles = $user->roles() ->where('roles.is_active', 1) ->pluck('roles.name') ->values() ->all(); return $this->respondSuccess([ 'user' => [ 'id' => (int) $user->id, 'firstname' => $user->firstname, 'lastname' => $user->lastname, 'email' => $user->email, 'roles' => $roles, ], 'jwt' => [ 'access_token' => $jwtToken, 'token_type' => 'bearer', 'expires_in' => (int) config('jwt.ttl') * 60, ], 'sanctum' => [ 'access_token' => $sanctumToken, 'token_type' => 'bearer', ], ], 'Authenticated.'); } public function refresh(Request $request): JsonResponse { try { $newToken = JWTAuth::parseToken()->refresh(); } catch (\Throwable $e) { return $this->respondError('Token refresh failed.', 401); } return $this->respondSuccess([ 'access_token' => $newToken, 'token_type' => 'bearer', 'expires_in' => (int) config('jwt.ttl') * 60, ], 'Token refreshed.'); } public function me(): JsonResponse { $user = Auth::user(); if (!$user) { return $this->respondError('Unauthorized.', 401); } return $this->respondSuccess([ 'id' => (int) $user->id, 'firstname' => $user->firstname, 'lastname' => $user->lastname, 'email' => $user->email, ], 'OK'); } public function logout(Request $request): JsonResponse { $token = $request->bearerToken(); if ($token && substr_count($token, '.') === 2) { try { JWTAuth::setToken($token)->invalidate(); } catch (\Throwable $e) { // ignore invalidation errors } } $user = $request->user(); if ($user && method_exists($user, 'currentAccessToken')) { $current = $user->currentAccessToken(); if ($current) { $current->delete(); } } return $this->respondSuccess(null, 'Logged out.'); } }