Twilio supports HTTP Basic and Digest Authentication. This allows you to password protect your 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

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
response, Twilio will make the same request with an Authorization header.

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:

Turn on TLS on your server and configure your Twilio account to use HTTPS urls.

Twilio assembles its request to your application, including the final URL and any POST fields (if the request is a POST).

If your request is a POST, Twilio takes all the POST fields, sorts them by alphabetically by their name, and concatenates the parameter name and value to the end of the URL (with no delimiter).

Twilio takes the resulting string (the full URL with query string and all POST parameters) and signs it using HMAC-SHA1 and your AuthToken as the key.

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 re-assemble the data string by going through the exact same process. If our two hashes match, then the request was authentic. You can then be sure that all the data used to construct the hash, including the full URL, query string and POST parameters were all sent to you by Twilio. Here's how you would perform the validation on your end:

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 ?).

If the request is a POST, sort all of the POST parameters alphabetically (using Unix-style case-sensitive sorting order).

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.

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:

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: +14158675309

Caller: +14158675309

CallSid: CA1234567890ABCDE

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

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

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

CallSid: CA1234567890ABCDE

Caller: +14158675309

Digits: 1234

From: +14158675309

To: +18005551212

Append each POST variable, name and value, to the string with no delimiters:
> https://mycompany.com/myapp.php?foo=1&bar=2CallSidCA1234567890ABCDECaller+14158675309Digits1234From+14158675309To+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+14158675309Digits1234From+14158675309To+18005551212, 12345)

Now take the Base64 encoding of the hash value (so it's only ASCII characters):
> RSOYDt4T1cUTdK1PDd93/VVr8B8=

Compare that to the hash Twilio sent in the X-Twilio-Signature HTTP header. Match them up!

// Install the Java helper library from twilio.com/docs/java/installimportjava.util.HashMap;importjava.util.Map;importcom.twilio.sdk.TwilioUtils;publicclassExample{publicstaticvoidmain(String[]args){// Your Auth Token from twilio.com/user/accountStringauthToken="12345";// Initialize the validatorTwilioUtilsvalidator=newTwilioUtils(authToken);// The Twilio request URLStringurl="https://mycompany.com/myapp.php?foo=1&bar=2";// The post variables in Twilio's requestMap<String,String>params=newHashMap<>();params.put("CallSid","CA1234567890ABCDE");params.put("Caller","+14158675309");params.put("Digits","1234");params.put("From","+14158675309");params.put("To","+18005551212");// The X-Twilio-Signature header attached to the requestStringtwilioSignature="RSOYDt4T1cUTdK1PDd93/VVr8B8=";System.out.println(validator.validateRequest(twilioSignature,url,params));}}

# Download the twilio-python library from twilio.com/docs/python/installfromtwilio.securityimportRequestValidator# Your Auth Token from twilio.com/user/accountauth_token='12345'validator=RequestValidator(auth_token)url='https://mycompany.com/myapp.php?foo=1&bar=2'params={'CallSid':'CA1234567890ABCDE','Caller':'+14158675309','Digits':'1234','From':'+14158675309','To':'+18005551212'}# The X-Twilio-Signature header attached to the requesttwilio_signature='RSOYDt4T1cUTdK1PDd93/VVr8B8='print(validator.validate(url,params,twilio_signature))

<?php// Your auth token from twilio.com/user/account$authToken='12345';// Download the twilio-php library from twilio.com/docs/php/install, include it // hererequire_once('/path/to/twilio-php/Services/Twilio.php');$validator=newServices_Twilio_RequestValidator($authToken);// The Twilio request URL. You may be able to retrieve this from // $_SERVER['SCRIPT_URI']$url='https://mycompany.com/myapp.php?foo=1&bar=2';// The post variables in the Twilio request. You may be able to use // $postVars = $_POST$postVars=array('CallSid'=>'CA1234567890ABCDE','Caller'=>'+14158675309','Digits'=>'1234','From'=>'+14158675309','To'=>'+18005551212');// The X-Twilio-Signature header - in PHP this should be // $_SERVER["HTTP_X_TWILIO_SIGNATURE"];$signature='RSOYDt4T1cUTdK1PDd93/VVr8B8=';if($validator->validate($signature,$url,$postVars)){echo"Confirmed to have come from Twilio.";}else{echo"NOT VALID. It might have been spoofed!";}

# Get twilio-ruby from twilio.com/docs/ruby/installrequire'rubygems'# This line not needed for ruby > 1.8require'twilio-ruby'# Get your Auth Token from https://www.twilio.com/consoleauth_token='your_auth_token'validator=Twilio::Util::RequestValidator.new(auth_token)url='https://mycompany.com/myapp.php?foo=1&bar=2'params={'CallSid'=>'CA1234567890ABCDE','Caller'=>'+14158675309','Digits'=>'1234','From'=>'+14158675309','To'=>'+18005551212'}# The X-Twilio-Signature header attached to the requesttwilio_signature='RSOYDt4T1cUTdK1PDd93/VVr8B8='print(validator.validate(url,params,twilio_signature))

// Install the Java helper library from twilio.com/docs/java/installimportjava.util.HashMap;importjava.util.Map;importcom.twilio.security.RequestValidator;publicclassExample{publicstaticvoidmain(String[]args){// Your Auth Token from twilio.com/user/accountStringauthToken="12345";// Initialize the validatorRequestValidatorvalidator=newRequestValidator(authToken);// The Twilio request URLStringurl="https://mycompany.com/myapp.php?foo=1&bar=2";// The post variables in Twilio's requestMap<String,String>params=newHashMap<>();params.put("CallSid","CA1234567890ABCDE");params.put("Caller","+14158675309");params.put("Digits","1234");params.put("From","+14158675309");params.put("To","+18005551212");// The X-Twilio-Signature header attached to the requestStringtwilioSignature="RSOYDt4T1cUTdK1PDd93/VVr8B8=";System.out.println(validator.validate(url,params,twilioSignature));}}

<?php// NOTE: This example uses the next generation Twilio helper library - for more// information on how to download and install this version, visit// https://www.twilio.com/docs/libraries/phprequire_once'/path/to/vendor/autoload.php';useTwilio\Security\RequestValidator;// Your auth token from twilio.com/user/account$token="12345";// The X-Twilio-Signature header - in PHP this should be// $_SERVER["HTTP_X_TWILIO_SIGNATURE"];$signature='RSOYDt4T1cUTdK1PDd93/VVr8B8=';// Initialize the validator$validator=newRequestValidator($token);// The Twilio request URL. You may be able to retrieve this from// $_SERVER['SCRIPT_URI']$url='https://mycompany.com/myapp.php?foo=1&bar=2';// The post variables in the Twilio request. You may be able to use// $postVars = $_POST$postVars=array('CallSid'=>'CA1234567890ABCDE','Caller'=>'+14158675309','Digits'=>'1234','From'=>'+14158675309','To'=>'+18005551212');if($validator->validate($signature,$url,$postVars)){echo"Confirmed to have come from Twilio.";}else{echo"NOT VALID. It might have been spoofed!";}

# Download the twilio-python library from twilio.com/docs/python/installfromtwilio.utilimportRequestValidator# Your Auth Token from twilio.com/user/accountauth_token='12345'validator=RequestValidator(auth_token)url='https://mycompany.com/myapp.php?foo=1&bar=2'params={'CallSid':'CA1234567890ABCDE','Caller':'+14158675309','Digits':'1234','From':'+14158675309','To':'+18005551212'}# The X-Twilio-Signature header attached to the requesttwilio_signature='RSOYDt4T1cUTdK1PDd93/VVr8B8='print(validator.validate(url,params,twilio_signature))

# Get twilio-ruby from twilio.com/docs/ruby/installrequire'rubygems'# This line not needed for ruby > 1.8require'twilio-ruby'# Get your Auth Token from https://www.twilio.com/consoleauth_token='your_auth_token'validator=Twilio::Security::RequestValidator.new(auth_token)url='https://mycompany.com/myapp.php?foo=1&bar=2'params={'CallSid'=>'CA1234567890ABCDE','Caller'=>'+14158675309','Digits'=>'1234','From'=>'+14158675309','To'=>'+18005551212'}# The X-Twilio-Signature header attached to the requesttwilio_signature='RSOYDt4T1cUTdK1PDd93/VVr8B8='print(validator.validate(url,params,twilio_signature))

Validate Signature of Request

We highly recommend you use the helper libraries to do signature validation.
If you are curious what the libraries are doing under the hood, here is an
example written in PHP that you can copy:

<?php// Your auth token from twilio.com/user/account$authToken='456bef';publicfunctioncomputeSignature($url,$data=array()){// sort the array by keysksort($data);// append the data array to the url string, with no delimitersforeach($dataas$key=>$value){$url=$url.$key.$value;}// This function calculates the HMAC hash of the data with the key// passed in// Note: hash_hmac requires PHP 5 >= 5.1.2 or PECL hash:1.1-1.5// Or http://pear.php.net/package/Crypt_HMAC/$hmac=hash_hmac("sha1",$url,$authToken,true)returnbase64_encode($hmac);}

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.

For voice calls over HTTP, Twilio will drop the username and password (if
any) from the URL before computing the signature. For voice calls over HTTPS,
Twilio will drop the username, password and port (if any) 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.

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... https://mycompany.com/twilio/ for example. 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/.

// Install the Java helper library from twilio.com/docs/java/installimportjava.util.HashMap;importjava.util.Map;importcom.twilio.sdk.TwilioUtils;publicclassExample{publicstaticvoidmain(String[]args){// Your Auth Token from twilio.com/user/accountStringauthToken="12345";// Initialize the validatorTwilioUtilsvalidator=newTwilioUtils(authToken);// The Twilio request URLStringurl="https://mycompany.com/myapp.php?foo=1&bar=2";// The post variables in Twilio's requestMap<String,String>params=newHashMap<>();params.put("CallSid","CA1234567890ABCDE");params.put("Caller","+14158675309");params.put("Digits","1234");params.put("From","+14158675309");params.put("To","+18005551212");// The X-Twilio-Signature header attached to the requestStringtwilioSignature="RSOYDt4T1cUTdK1PDd93/VVr8B8=";System.out.println(validator.validateRequest(twilioSignature,url,params));}}

# Download the twilio-python library from twilio.com/docs/python/installfromtwilio.securityimportRequestValidator# Your Auth Token from twilio.com/user/accountauth_token='12345'validator=RequestValidator(auth_token)url='https://mycompany.com/myapp.php?foo=1&bar=2'params={'CallSid':'CA1234567890ABCDE','Caller':'+14158675309','Digits':'1234','From':'+14158675309','To':'+18005551212'}# The X-Twilio-Signature header attached to the requesttwilio_signature='RSOYDt4T1cUTdK1PDd93/VVr8B8='print(validator.validate(url,params,twilio_signature))

<?php// Your auth token from twilio.com/user/account$authToken='12345';// Download the twilio-php library from twilio.com/docs/php/install, include it // hererequire_once('/path/to/twilio-php/Services/Twilio.php');$validator=newServices_Twilio_RequestValidator($authToken);// The Twilio request URL. You may be able to retrieve this from // $_SERVER['SCRIPT_URI']$url='https://mycompany.com/myapp.php?foo=1&bar=2';// The post variables in the Twilio request. You may be able to use // $postVars = $_POST$postVars=array('CallSid'=>'CA1234567890ABCDE','Caller'=>'+14158675309','Digits'=>'1234','From'=>'+14158675309','To'=>'+18005551212');// The X-Twilio-Signature header - in PHP this should be // $_SERVER["HTTP_X_TWILIO_SIGNATURE"];$signature='RSOYDt4T1cUTdK1PDd93/VVr8B8=';if($validator->validate($signature,$url,$postVars)){echo"Confirmed to have come from Twilio.";}else{echo"NOT VALID. It might have been spoofed!";}

# Get twilio-ruby from twilio.com/docs/ruby/installrequire'rubygems'# This line not needed for ruby > 1.8require'twilio-ruby'# Get your Auth Token from https://www.twilio.com/consoleauth_token='your_auth_token'validator=Twilio::Util::RequestValidator.new(auth_token)url='https://mycompany.com/myapp.php?foo=1&bar=2'params={'CallSid'=>'CA1234567890ABCDE','Caller'=>'+14158675309','Digits'=>'1234','From'=>'+14158675309','To'=>'+18005551212'}# The X-Twilio-Signature header attached to the requesttwilio_signature='RSOYDt4T1cUTdK1PDd93/VVr8B8='print(validator.validate(url,params,twilio_signature))

// Install the Java helper library from twilio.com/docs/java/installimportjava.util.HashMap;importjava.util.Map;importcom.twilio.security.RequestValidator;publicclassExample{publicstaticvoidmain(String[]args){// Your Auth Token from twilio.com/user/accountStringauthToken="12345";// Initialize the validatorRequestValidatorvalidator=newRequestValidator(authToken);// The Twilio request URLStringurl="https://mycompany.com/myapp.php?foo=1&bar=2";// The post variables in Twilio's requestMap<String,String>params=newHashMap<>();params.put("CallSid","CA1234567890ABCDE");params.put("Caller","+14158675309");params.put("Digits","1234");params.put("From","+14158675309");params.put("To","+18005551212");// The X-Twilio-Signature header attached to the requestStringtwilioSignature="RSOYDt4T1cUTdK1PDd93/VVr8B8=";System.out.println(validator.validate(url,params,twilioSignature));}}

<?php// NOTE: This example uses the next generation Twilio helper library - for more// information on how to download and install this version, visit// https://www.twilio.com/docs/libraries/phprequire_once'/path/to/vendor/autoload.php';useTwilio\Security\RequestValidator;// Your auth token from twilio.com/user/account$token="12345";// The X-Twilio-Signature header - in PHP this should be// $_SERVER["HTTP_X_TWILIO_SIGNATURE"];$signature='RSOYDt4T1cUTdK1PDd93/VVr8B8=';// Initialize the validator$validator=newRequestValidator($token);// The Twilio request URL. You may be able to retrieve this from// $_SERVER['SCRIPT_URI']$url='https://mycompany.com/myapp.php?foo=1&bar=2';// The post variables in the Twilio request. You may be able to use// $postVars = $_POST$postVars=array('CallSid'=>'CA1234567890ABCDE','Caller'=>'+14158675309','Digits'=>'1234','From'=>'+14158675309','To'=>'+18005551212');if($validator->validate($signature,$url,$postVars)){echo"Confirmed to have come from Twilio.";}else{echo"NOT VALID. It might have been spoofed!";}

# Download the twilio-python library from twilio.com/docs/python/installfromtwilio.utilimportRequestValidator# Your Auth Token from twilio.com/user/accountauth_token='12345'validator=RequestValidator(auth_token)url='https://mycompany.com/myapp.php?foo=1&bar=2'params={'CallSid':'CA1234567890ABCDE','Caller':'+14158675309','Digits':'1234','From':'+14158675309','To':'+18005551212'}# The X-Twilio-Signature header attached to the requesttwilio_signature='RSOYDt4T1cUTdK1PDd93/VVr8B8='print(validator.validate(url,params,twilio_signature))

# Get twilio-ruby from twilio.com/docs/ruby/installrequire'rubygems'# This line not needed for ruby > 1.8require'twilio-ruby'# Get your Auth Token from https://www.twilio.com/consoleauth_token='your_auth_token'validator=Twilio::Security::RequestValidator.new(auth_token)url='https://mycompany.com/myapp.php?foo=1&bar=2'params={'CallSid'=>'CA1234567890ABCDE','Caller'=>'+14158675309','Digits'=>'1234','From'=>'+14158675309','To'=>'+18005551212'}# The X-Twilio-Signature header attached to the requesttwilio_signature='RSOYDt4T1cUTdK1PDd93/VVr8B8='print(validator.validate(url,params,twilio_signature))