Xero Webhook验证失败:如何移除响应中的Cookie以完成验证
Hey there, let's tackle that "Response contained a cookie" error you're hitting with Xero Webhook validation. The core issue here is that Xero's Webhook service expects your endpoint to return only a plain HTTP status code—no cookies, no extra HTML, no extra response headers of any kind. Your current code sets the status, but your PHP environment (or prior code logic) is automatically adding cookies (like PHPSESSID from sessions) to the response.
Here's how to fix it step by step:
1. Clear all existing cookies before sending the response
Even if you didn't explicitly set cookies, your server might be sending session cookies or other auto-generated ones. We can expire them all upfront:
// Expire every existing cookie for the domain/path foreach ($_COOKIE as $name => $value) { setcookie($name, '', time() - 3600, '/'); setcookie($name, '', time() - 3600); // Cover different path scenarios }
2. Disable or destroy active sessions
If your script (or server config) starts a session automatically (via session_start() or session.auto_start in php.ini), PHP will send a PHPSESSID cookie without you noticing. Fix this:
// Check if a session is active and clean it up if (session_status() === PHP_SESSION_ACTIVE) { session_destroy(); // Expire the session cookie too setcookie(session_name(), '', time() - 3600, '/'); }
If session.auto_start is enabled in your php.ini, you'll want to set it to Off for this endpoint (or globally if it's not needed elsewhere).
3. Update your validation code to be strict
Modify your existing code to include the above fixes, and use the more reliable http_response_code function instead of manually setting the status header:
// Step 1: Clear all cookies foreach ($_COOKIE as $name => $value) { setcookie($name, '', time() - 3600, '/'); } // Step 2: Clean up active sessions if (session_status() === PHP_SESSION_ACTIVE) { session_destroy(); setcookie(session_name(), '', time() - 3600, '/'); } // Step 3: Handle Webhook signature validation $body = file_get_contents('php://input'); $yourHash = base64_encode(hash_hmac('sha256', $body, 'gDgLpn+xqX7ojhCEq5xx1viAyy6nEa4CMuiQxcXf9ctAoLkscnh/b1Y3002JjIEHOvOEt3MBvx1VLHh6lzaiAA==', true)); if ($yourHash === $_SERVER['HTTP_X_XERO_SIGNATURE']) { http_response_code(200); } else { http_response_code(401); } // Ensure no extra output is sent after the status code exit;
Quick Notes:
- No accidental output: Make sure there are no spaces, newlines, or other characters before the
<?phpopening tag—even a single space can trigger headers to be sent early, including cookies. http_response_codevsheader: Thehttp_response_codefunction is standard in PHP 5.4+ and avoids potential header conflicts, making it the better choice here.
内容的提问来源于stack exchange,提问作者Logita Kurrey

