> For clean Markdown of any page, append .md to the page URL. > For a complete documentation index, see https://docs.benchling.com/in-vivo/overview/webhook-security/llms.txt. > For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.benchling.com/in-vivo/_mcp/server. # Webhook security Receiving Benchling In Vivo webhooks requires hosting a publicly accessible HTTPS endpoint that accepts `application/json` POST requests. Your endpoint should be protected using one of the authentication mechanisms supported by Benchling In Vivo, such as custom authentication headers. In addition to endpoint authentication, Benchling In Vivo includes a cryptographic signature with every webhook request. Verifying this signature provides an additional layer of security, allowing you to confirm that the request originated from Benchling In Vivo and that the payload has not been tampered with. ## Signature Verification Every webhook request includes a `Signature` HTTP header containing an HMAC-SHA256 signature of the request body. **Signature Details:** | | | | --------- | ------------------------------------------- | | Header | `Signature` | | Algorithm | HMAC-SHA256 | | Key | Your webhook’s `signing_secret` (plaintext) | | Data | The entire raw HTTP request body | | Output | Lowercase hexadecimal string | The signature is computed over the **entire JSON request body**, which includes all fields: ```json { "id": "whe_7E5H2v4X0hfhqLVmZg9HYZ", "client_id": "your-client-uuid", "event": "animal.created", "version": "2022-12-14", "created_at": "2024-01-15T10:30:00.000000Z", "payload": { "//": "event-specific data" } } ``` > **Warning** > > You must use the raw HTTP request body bytes exactly as received. Do not parse and re-serialize the JSON, as any changes to whitespace, field ordering, or numeric precision will invalidate the signature. ## Verifying Webhooks Manually To verify a webhook request is authentic: 1. Extract the `Signature` header from the incoming HTTP request 2. Get the raw request body as bytes (before any JSON parsing) 3. Compute HMAC-SHA256 using your `signing_secret` as the key 4. Convert the result to a lowercase hexadecimal string 5. Compare with the `Signature` header value using a constant-time comparison > **Note** > > The signature is sensitive to any changes in the request body. Even a small modification will produce a completely different signature. Do not alter the request body in any way before verifying. Most programming languages provide libraries for computing HMAC-SHA256 signatures. The following Node.js example demonstrates the verification process. This is provided as a reference only and may become outdated—consult your language’s documentation for current best practices. **Node.js Example:** ```javascript const crypto = require('crypto'); function verifyWebhook(requestBody, signatureHeader, signingSecret) { if (typeof signatureHeader !== 'string') return false; const expected = crypto .createHmac('sha256', signingSecret) .update(requestBody) .digest(); const provided = Buffer.from(signatureHeader, 'hex'); // timingSafeEqual throws on buffers of different lengths, so check first. // Use constant-time comparison to prevent timing attacks. return expected.length === provided.length && crypto.timingSafeEqual(expected, provided); } ``` > **Tip** > > Most web frameworks provide a way to access the raw request body. Ensure you capture this before any middleware parses the JSON.