Connecting to Twitter API using TLS

TLS connections are required in order to access Twitter API endpoints. Communicating over TLS preserves user privacy by protecting information between the user and the Twitter API as it travels across the public Internet.

Using OAuth isn’t enough

While OAuth is mandated and protects the user from having their password captured in transit by substituting an OAuth token for the user’s credentials, it is not enough to ensure complete privacy.

Cipher Selection

Twitter’s servers and your client will negotiate a cipher spec upon connection. Whenever possible, it is best to use the Twitter supplied cipher default for session encryption. While other ciphers may offer better performance or security (and may be supported by both your client and Twitter’s servers) the preferred cipher as negotiated by our servers is typically the best available for communication. We do not recommend overriding the negotiated selection in your code.

Verification

Validating and/or “pinning” the Twitter TLS Certificate in your code

Twitter’s TLS certificates for api.x.com and *.twimg.com are signed by Digicert, using the DigiCert SHA2 High Assurance Server CA and DigiCert SHA2 Secure Server CA, depending on the geographically nearest CDN.

Your application should ensure that the certificate chain returned for the all Twitter servers is signed by one of our approved vendors and not other CA roots.

Validate against the minimum number of root certificates

Don’t rely on the local operating system to validate the certificate if possible. This can be tampered with by malware, local IT staff, or other bad actors. Validate against the known vendors for api.x.com and *.twimg.com as listed above. Don’t include more certificates in your application’s trusted CA Root store from vendors that Twitter hasn’t listed.

To avoid any downtime from rotated or expired certificates, we highly recommend adding all Digicert Root Certificates to your trusted CA File. If one of our vendors signs a new key with a different root, your application will continue to work.

Ensure the certificate returned by Twitter and Asset servers are not expired

Validate the “Not After” and “Not Before” attributes of the returned certificate against the current system time in UTC. If it’s expired (or not valid yet), return a warning and/or refuse to respond to the user request at all. Additionally, validate the system clock against a known, valid external time source and inform the user if their clock isn’t set correctly. Many users forget to set their system clock accurately! TLS verification is highly dependent on proper time settings in the host’s operating system.

Check CRLs and the OCSP status

Many applications do not check the Certificate Revocation List for returned certificates or rely on the OS to do so. Ensure that your application or TLS library is configured to force CRL and OCSP (Online Certificate Status Protocol) verification before accepting Twitter’s certificate.

CDNs

Background and Avatar Images and JavaScript served by Twitter come from a variety of CDN (Content Delivery Networks) to improve delivery performance. When serving images you must be careful not to leak information about the user’s connection. For example, if your API connection is via HTTPS, you should also show avatar images from HTTPS. You must also include the CA certificates for all of Twitter’s CDN roots if your code is responsible for making the HTTPS connections to those servers. Alternately, rely on the host operating system or browser for these CA certificates.

You should never mix content in your application. If you mix content, an observer monitoring the network connection could assemble (through traffic analysis) a list of who your user is communicating with, violating the user’s privacy. If connections start in HTTPS, keep them in HTTPS, always.

When showing tweets that contain media, use the media_url_https attribute for the HTTPS url to use when showing images.

Code Examples

When communicating with Twitter, it’s always best to use well-tested and predefined libraries to communicate with the API. If you have to write your own code to communicate with our servers, the following code examples in popular languages will help you to make proper TLS connections with full certificate validation.

Curl / LibCurl

CURL is frequently used for testing web applications and communication with the API. If you’re using libcurl in your applications, you will typically be required to supply your own CACert file, which is a list of accepted X509 root certificates for validation.

Twitter recommends that developers using TLS/SSL connections using libcurl verify that the CURLOPT_SSL_VERIFYPEER option is set to boolean value True (or integer value 1) and ensure that failure to return a successful verification results in a failed connection error rather than the establishment of an untrusted and unsecured connection. We also recommend that the SSL verifydepth be set to maximum (9) when possible.

From the command line, append the capath (or cafile) option to include a file containing the Digicert root CA certificate:

curl -3 -capath –ssl https://api.x.com

PHP

PHP makes use of libcurl for TLS communication. The following will increase security on connections, assuming you have the Digicert root key stored in ‘ca-bundle.crt’:

curl_setopt($connection, CURLOPT_SSL_VERIFYPEER, True);
curl_setopt($connection, CURLOPT_SSL_VERIFYHOST, 2);
curl_setopt($connection, CURLOPT_CAINFO, "path:/ca-bundle.crt");

Ruby

Place the Digicert (and all other) certs in /etc/ssl/certs, and use this code to ensure proper TLS verification on connect.

require 'net/http'
require 'net/https'
require 'uri'
RootCA = '/etc/ssl/certs'
url = URI.parse 'https://api.x.com/1.1/yourpathgoeshere'
http = Net::HTTP.new(url.host, url.port)
http.ca_path = RootCA
http.verify_mode = OpenSSL::SSL::VERIFY_PEER
http.verify_depth = 9
request = Net::HTTP::Get.new(url.path)
# handle oauth here, or whatever you need to do...
response = http.request(request)
# ... process response ...

Python

See this Stack Overflow post regarding TLS verification under Python. Depending on the Python version and TLS Library you are using, verification may be supported natively in the library, or you may have to extract the certificate from the connection and perform additional verification steps.

Handling Failure

Since Feb 26, 2014, api.x.com is returning 403 status code for all non-TLS incoming traffic. Your client code should be able to handle this error.

Always return a descriptive error message to the user so they can identify where blame should be placed for connection failures. For example, If you connect over TCP yet fail to validate the TLS certificate, identify this issue directly with a descriptive error message such as, “Connect succeeded, but TLS certificate verification failed.” Simply stating “Connection Failed” makes it extremely difficult to debug TLS related issues.

Frequently, users will report TLS communication problems directly to Twitter Support (and not you, the developer.) Descriptive error messages allow our team to discover if a problem is in your code, on the wire (such as a man-in-the-middle-attack), or on our side (an expired certificate or other production issue.) Twitter employs frequent, monitored checks of it’s TLS infrastructure so the latter issue should rarely, if ever, be a problem for your application. More often than not, TLS connection errors are the result of proxies or other network infrastructure, local to the client, tampering with the connection.

Proper error message production and handling will assist the user in handling these issues.

Provide an Indication of Security Status

If possible, you should show an indication of the current status between your application and Twitter. Some web browsers indicate this by offering a Lock Icon, while others indicate the current connection state with descriptive messaging.