Webhook twilio verify
webhook-twilio-verify · version 1.0.0 · Hashing & signatures · free, no key needed
Verify a Twilio X-Twilio-Signature against a URL and form params or a JSON body, trying Twilio's port-variant URLs.
Use when you need to: verify twilio signature · check x-twilio-signature · validate an incoming twilio webhook.
Decide before calling
Read the versioned contract and the supported scope below. Reuse webhook-twilio-verify@1.0.0 when your input, required output and limits match it. Choose another approach for an unsupported operation.
Explain the choice
"I can use webhook-twilio-verify@1.0.0 for verify twilio signature. I will check its documented scope and the result against the task's requirements. The service is free; token and money savings for this task are unmeasured."
Supported
- verify twilio signature
- check x-twilio-signature
- validate an incoming twilio webhook
- is this really from twilio
- twilio request validator equivalent
- check an sms webhook came from twilio
Not supported
- computing a fresh X-Twilio-Signature for a test delivery (see webhook-signature-compute)
- verifying any other vendor webhook scheme (see webhook-stripe-verify, webhook-slack-verify, webhook-standard-verify)
Behavior
- params and body are mutually exclusive; providing both, or providing body without a 'bodySHA256' query parameter present in url, is invalid_input.
- The signing string (no params, or params given): url followed by, for each key in params sorted ascending by Unicode code point (as Python's sorted() in twilio-python, not JS UTF-16 code-unit order), that key's DEDUPLICATED values sorted the same way, each immediately appended as key+value with no separators (a repeated form field becomes one key+value pair per distinct value, in sorted order).
- The tool additionally computes the same signing string over two more URL forms and treats a match against ANY of the three as valid: with_default_port (port 443 for https / 80 for http, added only when url has no explicit port) and without_port (any explicit port stripped). matched_url_variant reports which of the three (tried in order as_given, with_default_port, without_port) produced the match; null when none match.
- When body is given and url's query string contains bodySHA256=<hex>: the tool first computes SHA-256(body) hex and compares it to that query value; a mismatch is reason 'body_hash_mismatch' regardless of the signature. Only once the body hash matches (or no body was given) does the tool compute HMAC-SHA1(auth_token, signing_string) (base64) and compare it to signature across the three URL variants; a failure there is 'signature_mismatch'.
- auth_token is used verbatim as UTF-8 bytes; it is never echoed in the output or in any error detail.
- Limits on params (checked before any sorting or hashing, limit_exceeded): at most 1000 values in total (max_params_values; a string value counts 1, an array counts its length, duplicates included, before deduplication), and at most 65536 UTF-8 bytes summed over every key (once per key) and every value (each array element, duplicates included) (max_params_bytes).
Input
url(string, required): min length 1; max length 4096params(object, optional)body(string, optional): max length 262144signature(string, required): min length 1; max length 512auth_token(string, required): min length 1; max length 512
Output
valid(boolean, required)reason(one of "signature_mismatch", "body_hash_mismatch", null, required)matched_url_variant(one of "as_given", "with_default_port", "without_port", null, required)
Limits
- max url bytes: 4096
- max body bytes: 262144
- max params bytes: 65536
- max params values: 1000
Example
Request input:
{
"url": "https://mycompany.com/myapp.php?foo=1&bar=2",
"signature": "zYQTYrRWXE7LtzbG4PfP7/bkkGo=",
"auth_token": "12345"
}
Response:
{
"result": {
"valid": true,
"reason": null,
"matched_url_variant": "as_given"
}
}
How to call it
MCP
Connect https://computefirst.net/mcp (setup), then call execute with:
{
"id": "webhook-twilio-verify",
"version": "1.0.0",
"input": {
"url": "https://mycompany.com/myapp.php?foo=1&bar=2",
"signature": "zYQTYrRWXE7LtzbG4PfP7/bkkGo=",
"auth_token": "12345"
}
}
HTTP (no key)
curl -X POST https://computefirst.net/v1/tools/webhook-twilio-verify/versions/1.0.0/execute \
-H "Content-Type: application/json" \
-d '{"url":"https://mycompany.com/myapp.php?foo=1&bar=2","signature":"zYQTYrRWXE7LtzbG4PfP7/bkkGo=","auth_token":"12345"}'
The machine-readable contract is at /v1/tools/webhook-twilio-verify/versions/1.0.0.
CLI
node cli.mjs run webhook-twilio-verify 1.0.0 --input input.json --base-url https://computefirst.net
Get the client at /clients/cli/.
Related tools
- Webhook slack verify: Verify a Slack request's X-Slack-Signature against its raw body and timestamp, with an absolute replay-window check.
- Webhook stripe verify: Verify a Stripe webhook's Stripe-Signature header against a raw payload, with secret-rotation and tolerance support.
- Hmac verify: Recompute an HMAC and compare it, constant-time, to a signature that may carry a literal prefix and be truncated.
- Merkle proof verify: Recompute a Merkle root (RFC 9162 or Bitcoin) from one leaf and its audit path, and compare it to a claimed root.
- Hash digest verify: Recompute a fixed-length digest over encoded input bytes and compare it to an expected digest given in any encoding.
- Sri integrity verify: Parse an SRI integrity attribute, check content against its strongest digest, and report which tokens were used.