How to secure Twilio webhook URLs in Node.js

Twilio’s APIs allow developers to reinvent communications with things like programmable phone calls, SMS or intelligent chatbots. Developers can build applications to interact with their users and react to their responses. To respond to events like incoming messages, you can define a webhook URL. A webhook is an HTTP request that Twilio performs to find out what the reaction to a Twilio even like an incoming SMS should be. Your defined HTTP endpoints have to respond with a Twilio-understandable configuration language called TwiML (Twilio Markup Language).

These endpoints can be hosted anywhere as long as they’re available publicly and accessible by Twilio’s infrastructure.

Three ways to secure your webhook URLs

Let’s assume you built a rating application that allows users to rate an event they’re at by sending an SMS to a certain number. Every incoming SMS to your number triggers a webhook to your infrastructure that can write the included data to disk.

Unfortunately, an evil hacker found your webhook HTTP endpoint and recognizes the responded TwiML response as Twilio configuration. The hacker is now able to make requests to your application, which messes with the result of your event rating and makes it useless.

Securing your webhook URLs is always recommended. But as the Twilio docs describe, it’s crucial if you expose sensitive data or mutate existant datasets like in our rating example. How can you make sure only Twilio is interacting with your endpoints?

First, make sure you’re using HTTPS. Man-in-the-middle attacks are a common risk, and if you’re not serving your Twilio configuration over a secure connection, you can never be sure that a third party didn’t alter it. What you could do additionally is to secure your endpoints with HTTP authentication. This way your webhook URLs are not accessible without a username/password combination in the first place.

A third option is to validate if the incoming requests were sent by Twilio using the X-Twilio-Signature header which is the core of this article. Let’s have a look at how this works in detail!

The X-Twilio-Signature header

When Twilio sends a request to your defined webhook URL, it will include the x-twilio-signature header. This header is an encoded string representing the request URL and the sorted request parameters. The resulted string is then signed using HMAC-SHA1 using your AuthToken as the key. The AuthToken is crucial here because its value is only accessible to Twilio and yourself. A third party can not generate the same hashed Twilio signature without having access to it.

To validate incoming requests, you can perform the same signature procedure and compare if your generated signature and the sent signature match. If they do, you can be sure that Twilio sent the request you received.

Sidenote: in case you’re using serverless functions via Twilio Runtime, you might have seen the access control setting, which enables Twilio signature validation for every incoming request.

X-Twilio-Signature validation using the Twilio Node.js helper library

To make it as easy as possible, the Twilio Node.js helper library not only provides you with functionality to build TwiML responses or interact with the API endpoints, it also includes the feature to validate requests.

To get started, make sure you installed the library.