Cloud services are becoming more and more important resources for computer applications and many mobile and desktop tools use them for many purposes. Most of such cloud platforms require the authentication of the users, that must be secure and reliable. OAuth is a mean to authenticate a mobile or desktop application to a cloud platform. Examples of cloud services using OAuth for the application authentication are Twitter and Dropbox.
For a physicist (for any scientist in general) cloud services are useful to exchange data and to remotely control scientific instruments. For example, suppose you are responsible for monitoring the temperature of a data center. You may want to be notified when the temperature exceeds a given threshold. Any application running in your data center can measure the local temperature and, if needed, send an e-mail to you. However, it is very possible that you are not reading your e-mails at that moment. A possibility is to have a twitter mobile app on your phone that let you know when someone mention you on his timeline as soon as it happens. The notification is usually in the form of a sound and/or vibration of your phone.
Then, you can have a process running in the data center monitoring the temperature; if the temperature exceeds the threshold, the application post a tweet on a dedicated timeline with a mention to you and you suddenly receive a notification.
In order for the application to post a message on twitter, it must be authenticated. This is done using OAuth. First of all, once you created the user on twitter, you must allow applications to take actions on it. You can do that creating an App visiting http://twitter.com/apps. When you create an App, four important keys are generated from the system: the consumer’s key and secret as well as the access token key and secret. They are four long strings of apparently random characters. You can take them as a sort of username/password pairs, needed for your application to authenticate itself with twitter.
Let’s see how to use them to post a tweet. The application can post a tweet using a web service, i.e. reaching a given URL over the Internet to which the application passes a set of parameters, if any. curl, for example, is an application to do that. wget is and alternative. With curl, for example, you can do something like
and get the following
<HTML><HEAD><meta http-equiv="content-type" content="text/html;charset=utf-8"> <TITLE>302 Moved</TITLE></HEAD><BODY> <H1>302 Moved</H1> The document has moved <A HREF="http://www.google.it/?gfe_rd=cr&ei=2M3LVJiuBsms8wfhuIKwCQ">here</A>. </BODY></HTML>
i.e. the HTML source code of the required URL. In order to use curl to post on twitter you need to specify the corresponding twitter API URL (https://api.twitter.com/1.1/statuses/update.json) and few parameters. First of all you have to say curl which HTTP method to use to connect to the URL (POST). Then you must tell curl which data to associate with the request (in this case the text of the tweet, e.g. ‘This is a test’) as well as a set of information collected into the so-called header. The header contains authentication data.
The curl command to post a tweet looks like
curl --request 'POST' 'https://api.twitter.com/1.1/statuses/update.json' --data 'status=This%20is%20a%20test.' --header 'Authorization: OAuth ...'
where ellipsis are substituted by the actual header content discussed below. The data passed to the URL contains the body of the message in the form “status=…” where … is the URL-encoded message to post, i.e. the message you want to show in the user timeline where all special characters, included blanks, are converted in a format that can be transmitted over the Internet. The blanks of our message are converted into %20.
The hard work comes with the header. This is composed of various parts in the form key=value. First of all you need to include the consumer key as
Then, a field called nonce is expected. This field is an arbitrary string used only once to crypt information. There are many ways to define a nonce: one consists in taking the current time in Unix epoch and in encoding it using the base64 algorithm. In python, this can be done as
timestamp = str(int(time.time())) nonce = timestamp.encode("base64")rstrip('\n')
the rstrip method removes the last newline character from the encoded string. Now nonce is an apparently random string that may contain, however, characters not suitable to be transmitted over the Internet. Then, you need to URL-encode the string. Again, in python, you can do that with
nonce = urllib.quote_plus(nonce)
When you have the nonce, you add into your header as
The following field in the header is your crypted signature in the form
Before discussing how to generate the signature, let’s discuss other fields. The signature method must be passed as
followed by the timestamp in Unix epoch, as in
and the access token followed by the OAuth version as in
As a whole, the header looks like the following:
Authorization: OAuth oauth_consumer_key="yXaXpDXu...", oauth_nonce="60c64c10f849beb0b6fdc9ece8c83768", oauth_signature="9bnQYgeF12Q7%2BdBX...", oauth_signature_method="HMAC-SHA1", oauth_timestamp="1422633296", oauth_token="119003773-u1...", oauth_version="1.0"
Let’s then discuss how to generate the signature. It is an URL-encoded string containing a base64 encoded key generated applying the HMAC-SHA1 algorithm to the plain signature. The plain signature, in turn, is a an URL-encoded string containing the HTTP method, the API URL and a set of parameters composed of the consumer key, the nonce, the signature method, the access token and the version. Let’s look how to build it in python.
First of all, let’s build the plain signature as
parameters = 'oauth_consumer_key=' + consumer_key + '&oauth_nonce=' + nonce + \ '&oauth_signature_method=HMAC-SHA1&oauth_timestamp=' + timestamp + \ '&oauth_token=' + access_token + '&oauth_version=1.0' basestr = 'POST&' + urllib.quote_plus('https://api.twitter.com/1.1/statuses/update.json') + '&' + urllib.quote_plus(parameters) plainsignature = basestr + urllib.quote('&status=status=This%20is%20a%20test.')
Then encode the plain signature applying the HMAC-SHA1 algorithm using a combination of the consumer secret and access token secret in the form
key = consumer_secret + '&' + access_token_secret
The encoded signature can be obtained as
hashed = hmac.new(key, plainsignature, sha1)
that must be base64 encoded, then URL-encoded:
encoded_signature = urllib.quote_plus(hashed.digest().encode("base64").rstrip('\n'))
The encoded signature is the string to be used as a signature.
I wrote a python script to help people doing these kind of experiments. There are also pure shell scripts to retrieve the user timeline and to post tweets in a repository on bitbucket. You can find the software on https://bitbucket.org/organtin/go-twitter. It is still in the development phase and documentation is very poor, but it will improve rapidly.
Feel free to play with it and redistribute the code, if you like it.