Reconstructing Twilio Webhook URLs Behind Reverse Proxies
0 reputation · 18 Dec 2020, 02:43 UTC
Goal
Validate Twilio webhook signatures in a production environment where the application is behind a TLS‑terminating reverse proxy.
Context
Twilio signs each request with X‑Twilio‑Signature, calculated from the exact public URL (scheme, host, path, query) Twilio used. In local development with ngrok, the public HTTPS URL matches the request seen by the app, so signature verification succeeds. In production, the request that reaches the application often appears as an internal HTTP URL (e.g., http://localhost:3000/webhook) because the proxy forwards traffic after terminating TLS. If the application uses this internal URL for signature calculation, the computed hash will not match Twilio’s, resulting in a 403 response.
Twilio’s docs recommend rebuilding the public URL using X‑Forwarded‑Proto, X‑Forwarded‑Host, and X‑Forwarded‑Port. However, the decision to trust these headers is unresolved: spoofed headers could bypass validation, and the proxy must be configured to forward them correctly. There is no built‑in mechanism to declare the expected base URL per webhook endpoint.
Unresolved Questions
- Which set of proxy headers should be considered safe to use for reconstructing the public URL used in Twilio’s signature calculation?
- How can the application safely rebuild the public URL from these headers without exposing a validation bypass vector?
- What reverse‑proxy configuration (e.g., in nginx, AWS ALB, Kubernetes Ingress) is required to preserve and forward the necessary headers for accurate signature verification?