Skip to contentSkip to navigationSkip to topbar
On this pageProducts used

Security



Encrypted Communication

encrypted-communication page anchor

Twilio supports encryption to protect communications between Twilio and your web application. Just specify an HTTPS URL. Twilio will not connect to an HTTPS URL with a self-signed certificate, so use a certificate from a provider such as Let's Encrypt(link takes you to an external page)

(warning)

Warning

Be aware Twilio strongly recommends against pinning certificates. This is an outdated practice as certificates can be rotated at any time.

Twilio can use the HTTP protocol for callbacks - for instance, if you are working on a development environment that does not have SSL certificates installed. On your Twilio project's Settings page in the Console, the SSL Certificate Validation setting enforces validation on webhooks.

Here is the list of supported TLS ciphers for callbacks(link takes you to an external page).

(warning)

Warning

Twilio supports the TLS cryptographic protocol. Twilio cannot currently handle self-signed certificates, and support for SSLv3 is officially deprecated.


Twilio supports HTTP Basic and Digest Authentication. This allows you to password-protect the TwiML URLs on your web server so that only you and Twilio can access them. You may provide a username and password via the following URL format.

https://username:password@www.myserver.com/my_secure_document
(warning)

Warning

Twilio supports the TLS cryptographic protocol. Twilio cannot currently handle self-signed certificates, and support for SSLv3 is officially deprecated.

(warning)

Warning

Be careful to not include any special characters, such as &,``:, etc., in your username or password.

Twilio will authenticate to your web server using the provided username and password and will remain logged in for the duration of the call. We highly recommend that you use HTTP Authentication in conjunction with encryption. For more information on (link takes you to an external page)Basic and (link takes you to an external page)Digest Authentication, refer to your web server documentation.

If you specify a password-protected URL, Twilio will first send a request with no Authorization header. After your server responds with a 401 Unauthorized status code, a WWW-Authenticate header and a realm in the response, Twilio will make the same request with an Authorization header.

Example response from your server:

1
HTTP/1.1 401 UNAUTHORIZED
2
WWW-Authenticate: Basic realm="My Realm"
3
Date: Wed, 21 Jun 2017 01:14:36 GMT
4
Content-Type: application/xml
5
Content-Length: 327

Protect Media Access with HTTP Basic Authentication

protect-media-access-with-http-authentication page anchor

Media files, such as call recordings in Programmable Voice; or an image associated with any Programmable Messaging channel (eg. MMS, WhatsApp, or Facebook), can be stored in our Services.

Requiring HTTP Basic Authentication for stored media is considered industry best practice, and it is implemented by Twilio for all applicable Services. Some of our products such as Programmable Voice and Programmable Messaging, support HTTP Basic Authentication but aren't enabled by default. It is an opt-in setting that must be enabled for your applicable Twilio Account and sub-accounts.

To protect media access, you can enforce authentication to access them by enabling HTTP Basic Authentication in your Twilio Account. This setting requires your Twilio Account SID and Auth Token or API Key for all requests to access media files.

Twilio highly recommends enabling HTTP Basic Authentication for your media, especially if it contains Sensitive Data.

Please note, that you'll need to manually enable HTTP Basic Authentication for media access in the following Services and functionalities:

  • Programmable Messaging (ie. MMS, WhatsApp Facebook Business Messenger, Google Business, etc)
  • Programmable Voice (ie. call recordings)

The first step you should take to secure your web application is to ensure that you are using HTTPS for your web application's endpoint. Twilio will not connect to an HTTPS URL with a self-signed certificate, so use a certificate from a provider such as Let's Encrypt(link takes you to an external page)

Twilio can use the HTTP protocol for callbacks - for instance, if you are working on a development environment that does not have SSL certificates installed. On your Twilio project's Settings page in the Console, the SSL Certificate Validation setting enforces validation on webhooks.

Here is the list of supported TLS ciphers for callbacks(link takes you to an external page).


Validating Requests are coming from Twilio

validating-requests page anchor

If your application exposes sensitive data or is possibly mutative to your data, then you may want to be sure that the HTTP requests to your web application are indeed coming from Twilio, and not a malicious third party. To allow you this level of security, Twilio cryptographically signs its requests. Here's how it works:

  1. Turn on TLS on your server and configure your Twilio account to use HTTPS URLs.
  2. Twilio assembles its request to your application, including the final URL and any POST fields. * If your request is a POST , Twilio takes all the POST fields, sorts them alphabetically by their name, and concatenates the parameter name and value to the end of the URL (with no delimiter). Only query parameters get parsed to generate a security token, not the POST body. * If the request is a GET , the final URL includes all of Twilio's request parameters appended in the query string of your original URL using the standard delimiter & between the name/value pairs.
  3. Twilio takes the resulting string (the full URL with the scheme, port, query string and any POST parameters) and signs it using HMAC-SHA1 and your AuthToken as the key.
  4. Twilio sends this signature in an HTTP header called X-Twilio-Signature

Then, on your end, if you want to verify the authenticity of the request, you can leverage the built-in request validation method provided by all of our helper libraries:

Validate Signature of RequestLink to code sample: Validate Signature of Request
1
// Get twilio-node from twilio.com/docs/libraries/node
2
const client = require('twilio');
3
4
// Your Auth Token from twilio.com/console
5
const authToken = process.env.TWILIO_AUTH_TOKEN;
6
7
// Store Twilio's request URL (the url of your webhook) as a variable
8
const url = 'https://mycompany.com/myapp';
9
10
// Store the application/x-www-form-urlencoded parameters from Twilio's request as a variable
11
// In practice, this MUST include all received parameters, not a
12
// hardcoded list of parameters that you receive today. New parameters
13
// may be added without notice.
14
const params = {
15
CallSid: 'CA1234567890ABCDE',
16
Caller: '+12349013030',
17
Digits: '1234',
18
From: '+12349013030',
19
To: '+18005551212',
20
};
21
22
// Store the X-Twilio-Signature header attached to the request as a variable
23
const twilioSignature = 'Np1nax6uFoY6qpfT5l9jWwJeit0=';
24
25
// Check if the incoming signature is valid for your application URL and the incoming parameters
26
console.log(client.validateRequest(authToken, twilioSignature, url, params));

If the method call returns true, then the request can be considered valid and it is safe to proceed with your application logic.

(information)

Info

We highly recommend you use the helper libraries to do signature validation.

Explore the algorithm yourself

explore-the-algorithm-yourself page anchor

Here's how you would perform the validation on your end:

  1. Take the full URL of the request URL you specify for your phone number or app, from the protocol (https...) through the end of the query string (everything after the ?).
  2. If the request is a POST , sort all the POST parameters alphabetically (using Unix-style case-sensitive sorting order).
  3. Iterate through the sorted list of POST parameters, and append the variable name and value (with no delimiters) to the end of the URL string.
  4. Sign the resulting string with HMAC-SHA1 using your AuthToken as the key (remember, your AuthToken's case matters!).
  5. Base64 encodes the resulting hash value.
  6. Compare your hash to ours, submitted in the X-Twilio-Signature header. If they match, then you're good to go.

Let's walk through an example request. Let's say Twilio made a POST to your application as part of an incoming call webhook:

https://mycompany.com/myapp.php?foo=1&bar=2

And let's say Twilio posted some digits from a Gather to that URL, in addition to all the usual POST fields:

  • Digits : 1234
  • To : +18005551212
  • From : +14158675310
  • Caller : +14158675310
  • CallSid : CA1234567890ABCDE

Create a string that is your URL with the full query string:

https://mycompany.com/myapp.php?foo=1&bar=2

Then, sort the list of POST variables by the parameter name (using Unix-style case-sensitive sorting order):

  • CallSid : CA1234567890ABCDE
  • Caller : +14158675310
  • Digits : 1234
  • From : +14158675310
  • To : +18005551212

Next, append each POST variable, name and value, to the string with no delimiters:

https://mycompany.com/myapp.php?foo=1&bar=2CallSidCA1234567890ABCDECaller+14158675310Digits1234From+14158675310To+18005551212

Hash the resulting string using HMAC-SHA1, using your AuthToken Primary as the key.

Let's suppose your AuthToken is 12345. Then take the hash value returned from the following function call (or its equivalent in your language of choice):

hmac_sha1(https://mycompany.com/myapp.php?foo=1&bar=2CallSidCA1234567890ABCDECaller+14158675310Digits1234From+14158675310To+18005551212, 12345)

Now take the Base64 encoding of the hash value (so it's only ASCII characters):

GvWf1cFY/Q7PnoempGyD5oXAezc=

Finally, compare that to the hash Twilio sent in the X-Twilio-Signature HTTP header. If they match, the request is valid!

(warning)

Warning

This example is for illustrative purposes only. When validating requests in your application, only use the provided helper methods.

  • If the Content-Type is application-json, don't use the JSON body to fill in the validator's param for POST parameters.
    • The query parameter bodySHA256 will be included in the request.
    • Its value is calculated as the hexadecimal representation of the SHA-256 hash of the request body.
  • Some frameworks may trim whitespace from POST body fields. A notable example is Laravel, which has the TrimStrings middleware enabled by default. You must disable these behaviors to successfully match signatures generated from fields that have leading or trailing whitespace. Certain Node.js middleware may also trim whitespace from requests.
    • When manually constructing the request body to be sent (as can be done in the Studio HTTP Request widget) ensure that no hidden whitespaces are in the body.
  • When creating the hash make sure you are using your Primary AuthToken as the key. If you have recently created a secondary AuthToken, this means you still need to use your old AuthToken until the secondary one has been promoted to your primary AuthToken(link takes you to an external page) .
  • The HMAC-SHA1 secure hashing algorithm should be available in all major languages, either in the core or via an extension or package.
  • If your URL uses an "index" page, such as index.php or index.html to handle the request, such as: https://mycompany.com/twilio where the real page is served from https://mycompany.com/twilio/index.php , then Apache or PHP may rewrite that URL so it has a trailing slash, e.g., https://mycompany.com/twilio/ . Using the code above, or similar code in another language, you could end up with an incorrect hash, because Twilio built the hash using https://mycompany.com/twilio and you may have built the hash using https://mycompany.com/twilio/ .
  • For SMS and voice callbacks over HTTP:
    • Twilio will drop the username and password (if any) from the URL before computing the signature.
    • Twilio will keep the port (if any) in the URL when computing the signature.
  • For SMS callbacks over HTTPS:
    • Twilio will drop the username and password (if any) from the URL before computing the signature.
    • Twilio will keep the port (if any) in the URL when computing the signature.
  • For voice callbacks over HTTPS:
    • Twilio will drop the username and password (if any) from the URL before computing the signature.
    • Twilio will also drop the port (if any) from the URL before computing the signature.
  • For voice WSS handshake requests:
    • If you are having trouble verifying a WebSocket handshake request (e.g., for Programmable Voice Media Streams ), try appending a trailing / character to the URL that you pass to the signature validation method.

This behavior will continue to be supported in the 2008-08-01 and 2010-04-01 versions of the API to ensure compatibility with existing code. We understand this behavior is inconsistent, and apologize for the inconvenience.

(information)

A note on HMAC-SHA1

Concerned about SHA1 security issues? Twilio does not use SHA-1 alone.

In short, the critical component of HMAC-SHA1 that distinguishes it from SHA-1 alone is the use of your Twilio AuthToken as a complex secret key. While there are possible collision-based attacks on SHA-1(link takes you to an external page), HMACs(link takes you to an external page) are not affected by those same attacks - it's the combination of the underlying hashing algorithm (SHA-1) and the strength of the secret key (AuthToken) that protects you in this case.


Test the validity of your webhook signature

test-the-validity-of-your-webhook-signature page anchor
(information)

Info

It's a great idea to test your webhooks and ensure that their signatures are secure. The following sample code can test your unique endpoint against both valid and invalid signatures.

To make this test work for you, you'll need to:

  1. Set your Auth Token(link takes you to an external page) as an environment variable
  2. Set the URL to the endpoint you want to test
  3. If testing BasicAuth, change HTTPDigestAuth to HTTPBasicAuth
Test the validity of your webhook signatureLink to code sample: Test the validity of your webhook signature
1
// Get twilio-node from twilio.com/docs/libraries/node
2
const webhooks = require('twilio/lib/webhooks/webhooks');
3
const request = require('request');
4
5
// Your Auth Token from twilio.com/console
6
const authToken = process.env.TWILIO_AUTH_TOKEN;
7
8
// The Twilio request URL
9
const url = 'https://mycompany.com/myapp';
10
11
// The post variables in Twilio's request
12
const params = {
13
CallSid: 'CA1234567890ABCDE',
14
Caller: '+12349013030',
15
Digits: '1234',
16
From: '+12349013030',
17
To: '+18005551212',
18
};
19
20
21
function testUrl(method, url, params, valid) {
22
if(method === "GET") {
23
url += "?" + Object.keys(params).map(key => key + '=' + params[key]).join('&');
24
params = {};
25
}
26
const signatureUrl = valid ? url : "http://invalid.com";
27
const signature = webhooks.getExpectedTwilioSignature(authToken, signatureUrl, params);
28
const options = {
29
method: method,
30
url: url,
31
form: params,
32
headers: {
33
'X-Twilio-Signature': signature
34
}
35
}
36
37
request(options, function(error, response, body){
38
const validStr = valid ? "valid" : "invalid";
39
console.log(`HTTP ${method} with ${validStr} signature returned ${response.statusCode}`);
40
});
41
}
42
43
testUrl('GET', url, params, true);
44
testUrl('GET', url, params, false);
45
testUrl('POST', url, params, true);
46
testUrl('POST', url, params, false);

Validation using the Twilio Helper Libraries

validation-with-libraries page anchor

All the official Twilio Helper Libraries ship with a Utilities class which facilitates request validation. Head over to the libraries page to download the library for your language of choice.

Your Auth Token

auth-token page anchor

Please keep your AuthToken secure. It not only enables access to the REST API but also to request signatures. Learn how to secure this token using environment variables.

Need some help?

Terms of service

Copyright © 2024 Twilio Inc.