OAuth 1.0a in librest

Because the world is rapidly moving to OAuth 1.0a exclusively after a rather painful attack was discovered against 1.0, I've recently been updating our bling HTTP/REST/XML IPC library librest to support it. In particular Twitter only supports 1.0a, and Fire Eagle shows the user a very scary message unless 1.0a is used. Now that the code is finished I thought I'd give a example of the new API when used with Twitter.

#include <rest/oauth-proxy.h>

Including the OAuthProxy headers is a good start.

int
main (int argc, char **argv)
{
  GError *error = NULL;
  RestProxy *proxy;

  g_thread_init (NULL);
  g_type_init ();

  proxy = oauth_proxy_new ("UfXFxDbUjk41scg0kmkFwA",
                           "pYQlfI2ZQ1zVK0f01dnfhFTWzizBGDnhNJIw6xwto",
                           "https://twitter.com/", FALSE);

First, initalise the GLib threading and type system. Threading is required by libsoup at the moment because it will use threads to lookup names in the background, I imagine this requirement will disappear with the next GLib release.

Next, an OAuthProxy is created. The two strings of garbage are our OAuth Consumer Key and Consumer Secret, then the URL endpoint to access and FALSE to say that this URL is complete and doesn't require expansion. Yes, that was Consumer Secret. Not very secret, is it.

  if (!oauth_proxy_request_token (OAUTH_PROXY (proxy), "oauth/request_token", "oob", &error))
    g_error ("Cannot get request token: %s", error->message);

Here we ask for a Request Token. The function to call is oauth/request_token, and because this is a basic test application which doesn't support URI callbacks we're setting the callback URI to oob (out-of-band). It is the callback URI argument that tells the server that we're using OAuth 1.0a, in 1.0 this parameter (oauth_callback at the HTTP leve) doesn't exist.

The callback is used to pass from the server to the client a verifier which is then required to obtain the Access Token. In the case of Twitter, this is a seven digit number. If a URI was specified then it would be invoked with the verifier as a query argument, but because we're getting it out-of-band Twitter will show it to the user and ask them to enter it into the application.

  g_print ("Go to http://twitter.com/oauth/authorize?oauth_token=%s then enter the PIN\n",
           oauth_proxy_get_token (OAUTH_PROXY (proxy)));
  fgets (pin, sizeof (pin), stdin);
  g_strchomp (pin);

Here we tell the user to go to the authorisation URL (to which we add the request token we have so far), and then enter the PIN that Twitter gives them.

  if (!oauth_proxy_access_token (OAUTH_PROXY (proxy), "oauth/access_token", pin, &error))
    g_error ("Cannot get access token: %s", error->message);

Now we ask for an Accesss Token. The function to call is oauth/access_token, and we're passing the PIN the user entered as the validator. If we were using OAuth 1.0 then the validator would be NULL.

If this method succeeds then we have an Access Token, and are authenticated. To avoid the authentication dance the Access Token and Token Secret should be saved somewhere secure (gnome-keyring would be a good idea) for future use.

  RestProxyCall *call;
  call = rest_proxy_new_call (proxy);
  rest_proxy_call_set_function (call, "statuses/update.xml");
  rest_proxy_call_set_method (call, "POST");
  rest_proxy_call_add_param (call, "status", "Hello from librest!");
  if (!rest_proxy_call_sync (call, &error))
    g_error ("Cannot make call: %s", error->message);
  return 0;
}

First a Call object is created, which encapsulates all of the data required to make a REST call. The function is set to status/update.xml, the HTTP method set to POST (the default is, logically, GET), and a status message is set as a parameter. We make a synchronous call, and we're done. The bonus of using OAuth to authorise with Twitter is that you get the nice "from whatever" annotations on the tweets, to promote your application.

The full source of this example is available in git, along with other examples for Flickr and Fire Eagle. If you want to understand the differences between OAuth 1.0 and 1.0a but don't fancy reading both specifications in full, I can heartily endorse An Idiots Guide To OAuth 1.0a.

NP: Simple Things, Zero 7

11:34 Tuesday, 04 Aug 2009 [#] [computers] ( comments)