Skip to contentSkip to navigationSkip to topbar
Rate this page:
On this page

Secure your Express app by validating incoming Twilio requests


In this guide we'll cover how to secure your Express(link takes you to an external page) application by validating incoming requests to your Twilio webhooks are, in fact, from Twilio.

Securing your Express app with Twilio Node SDK's(link takes you to an external page) is simple. The Twilio SDK comes with an Express middleware which is ready to use.

Let's get started!


Use Twilio Express request validation middleware

use-twilio-express-request-validation-middleware page anchor

The Twilio Node SDK includes a webhook() method which we can use as an Express middleware to validate incoming requests. When applied to an Express route, if the request is unauthorized the middleware will return a 403 HTTP response.

Use Twilio webhook middleware for Express apps that validates Twilio requests

use-twilio-webhook-middleware-for-express-apps-that-validates-twilio-requests page anchor

Confirm incoming requests to your Express routes are genuine with this custom middleware.


_41
// You can find your Twilio Auth Token here: https://www.twilio.com/console
_41
// Set at runtime as follows:
_41
// $ TWILIO_AUTH_TOKEN=XXXXXXXXXXXXXXXXXXX node index.js
_41
//
_41
// This will not work unless you set the TWILIO_AUTH_TOKEN environment
_41
// variable.
_41
_41
const twilio = require('twilio');
_41
const app = require('express')();
_41
const bodyParser = require('body-parser');
_41
const VoiceResponse = require('twilio').twiml.VoiceResponse;
_41
const MessagingResponse = require('twilio').twiml.MessagingResponse;
_41
_41
app.use(bodyParser.urlencoded({ extended: false }));
_41
_41
app.post('/voice', twilio.webhook(), (req, res) => {
_41
// Twilio Voice URL - receives incoming calls from Twilio
_41
const response = new VoiceResponse();
_41
_41
response.say(
_41
`Thanks for calling!
_41
Your phone number is ${req.body.From}. I got your call because of Twilio´s
_41
webhook. Goodbye!`
_41
);
_41
_41
res.set('Content-Type', 'text/xml');
_41
res.send(response.toString());
_41
});
_41
_41
app.post('/message', twilio.webhook(), (req, res) => {
_41
// Twilio Messaging URL - receives incoming messages from Twilio
_41
const response = new MessagingResponse();
_41
_41
response.message(`Your text to me was ${req.body.Body.length} characters long.
_41
Webhooks are neat :)`);
_41
_41
res.set('Content-Type', 'text/xml');
_41
res.send(response.toString());
_41
});
_41
_41
app.listen(3000);


Use a tunnel for your local development environment in order to use live Twilio webhooks

use-a-tunnel-for-your-local-development-environment-in-order-to-use-live-twilio-webhooks page anchor

If your Twilio webhook URLs start with https:// instead of http://, your request validator may fail locally when you use ngrok(link takes you to an external page) or in production if your stack terminates SSL connections upstream from your app. This is because the request URL that your Express application sees does not match the URL Twilio used to reach your application.

To fix this for local development with ngrok, use ngrok http 3000 to accept requests on your webhooks instead of ngrok https 3000.


Disable request validation during testing

disable-request-validation-during-testing page anchor

If you write tests for your Express routes those tests may fail for routes where you use the Twilio request validation middleware. Any requests your test suite sends to those routes will fail the middleware validation check.

To fix this problem we recommend passing {validate: false} to the validation middleware twilio.webhook() thus disabling it. In Express applications it's typical to use NODE_ENV as the value to use to determine the environment the application is running in. In the code example, when NODE_ENV is 'test', the validation middleware should be disabled.

Disable Twilio webhook middleware when testing Express routes.

disable-twilio-webhook-middleware-when-testing-express-routes page anchor

Use environment variable to disable webhook validation during testing.


_48
// You can find your Twilio Auth Token here: https://www.twilio.com/console
_48
// Set at runtime as follows:
_48
// $ TWILIO_AUTH_TOKEN=XXXXXXXXXXXXXXXXXXX node index.js
_48
//
_48
// This will not work unless you set the TWILIO_AUTH_TOKEN environment
_48
// variable.
_48
_48
const twilio = require('twilio');
_48
const app = require('express')();
_48
const bodyParser = require('body-parser');
_48
const VoiceResponse = require('twilio').twiml.VoiceResponse;
_48
const MessagingResponse = require('twilio').twiml.MessagingResponse;
_48
_48
const shouldValidate = process.env.NODE_ENV !== 'test';
_48
_48
app.use(bodyParser.urlencoded({ extended: false }));
_48
_48
app.post('/voice', twilio.webhook({ validate: shouldValidate }), (req, res) => {
_48
// Twilio Voice URL - receives incoming calls from Twilio
_48
const response = new VoiceResponse();
_48
_48
response.say(
_48
`Thanks for calling!
_48
Your phone number is ${req.body.From}. I got your call because of Twilio´s
_48
webhook. Goodbye!`
_48
);
_48
_48
res.set('Content-Type', 'text/xml');
_48
res.send(response.toString());
_48
});
_48
_48
app.post(
_48
'/message',
_48
twilio.webhook({ validate: shouldValidate }),
_48
(req, res) => {
_48
// Twilio Messaging URL - receives incoming messages from Twilio
_48
const response = new MessagingResponse();
_48
_48
response.message(`Your text to me was ${req.body.Body
_48
.length} characters long.
_48
Webhooks are neat :)`);
_48
_48
res.set('Content-Type', 'text/xml');
_48
res.send(response.toString());
_48
}
_48
);
_48
_48
app.listen(3000);


Validating requests to your Twilio webhooks is a great first step for securing your Twilio application. We recommend reading over our full security documentation for more advice on protecting your app, and the Anti-Fraud Developer's Guide in particular.

To learn more about securing your Express application in general, check out the security considerations page in the official Express docs.(link takes you to an external page)


Rate this page: