Rate this page:


Encrypted Communication

Twilio supports encryption to protect communications between Twilio and your web application. Just specify an HTTPS URL. Note: Twilio cannot currently handle self signed certificates.

Twilio supports the TLS cryptographic protocol. Support for SSLv3 is officially deprecated.

HTTP Authentication

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.

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 Basic and 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:

WWW-Authenticate: Basic realm="My Realm"
Date: Wed, 21 Jun 2017 01:14:36 GMT
Content-Type: application/xml
Content-Length: 327

Validating Requests are coming from Twilio

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 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 Request

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

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

        Explore the algorithm yourself

        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 of 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 encode 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 page:

        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:

        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:

        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(, 12345)

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


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

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

        A Few Notes

        • 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.
        • 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: where the real page is served from, then Apache or PHP may rewrite that URL so it has a trailing slash, e.g., Using the code above, or similar code in another language, you could end up with an incorrect hash, because Twilio built the hash using and you may have built the hash using
        • 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.

        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.

        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, HMACs 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

        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 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 signature

              Validation using the Twilio Helper Libraries

              All of 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

              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.

              Rate this page:

              Need some help?

              We all do sometimes; code is hard. Get help now from our support team, or lean on the wisdom of the crowd by visiting Twilio's Stack Overflow Collective or browsing the Twilio tag on Stack Overflow.


                    Thank you for your feedback!

                    Please select the reason(s) for your feedback. The additional information you provide helps us improve our documentation:

                    Sending your feedback...
                    🎉 Thank you for your feedback!
                    Something went wrong. Please try again.

                    Thanks for your feedback!