'required|email', 'password' => 'required' ]); if ($errors) { json_error('Validation Failed', 422, $errors); } $email = $data['email']; $password = $data['password']; // 2. DB Check (Using hash for lookup since email is encrypted) $db = Database::getInstance(); $emailHash = hash('sha256', strtolower($email)); $stmt = $db->prepare("SELECT * FROM users WHERE email_hash = ? LIMIT 1"); $stmt->execute([$emailHash]); $user = $stmt->fetch(); if (!$user || !password_verify($password, $user['password_hash'])) { json_error('بيانات الدخول غير صحيحة', 401); } // 3. Issue Token $secret = env('JWT_SECRET'); if (!$secret || strlen($secret) < 32) { error_log('FATAL: JWT_SECRET is missing or too short in .env'); json_error('Server configuration error', 500); } $payload = [ 'user_id' => $user['id'], 'tenant_id' => $user['tenant_id'], 'role' => $user['role'], 'exp' => time() + (15 * 60) // 15 minutes ]; $token = JWT::encode($payload, $secret); // 4. Update Refresh Token (Hashed before storage for security) $refreshToken = bin2hex(random_bytes(32)); $refreshTokenHash = hash('sha256', $refreshToken); $stmt = $db->prepare("UPDATE users SET refresh_token_hash = ? WHERE id = ?"); $stmt->execute([$refreshTokenHash, $user['id']]); json_success([ 'access_token' => $token, 'refresh_token' => $refreshToken, 'user' => [ 'id' => $user['id'], 'name' => (App\Core\Encryption::decrypt($user['name']) ?: $user['name']), 'email' => (App\Core\Encryption::decrypt($user['email']) ?: $user['email']) ] ], 'تم تسجيل الدخول بنجاح');