Wishful Coding

Didn't you ever wish your
computer understood you?

Twitter xAuth in Python using Twisted and Twitty Twister

This is the first post in what will most likely be a series of posts related to Twitter, POP3, SMTP and Twisted. This post will be about asynchronous authentication with Twitter using xAuth.

xAuth is a simplified form of OAuth. Instead of doing the dance, you use credentials(like basic auth), but exchange them for an access token. You need to send a request to api@twitter.com to enable it.

This technique is also applicable to getting OAuth tokens, although that is more complicated.

We are going to use Twitty Twister, which is a Twitter lib for Twisted which supports signing OAuth requests. It does not, however, include code for obtaining an access token.

To obtain the token, it is suggested to use an external library. But since my app is 100% Twisted, and most OAuth libs blocking, I had a problem right there. We don’t want to have our nice reactor sit idle while we request our token, do we?

The solution is to use python-oauth to make the request, but just before we send it, you call request.to_postdata() and use twisted.web.client.getPage to send the request in an asynchronous manner.

My main resources where: http://dev.twitter.com/pages/xauth http://github.com/simplegeo/python-oauth2#readme http://twistedmatrix.com/documents/10.1.0/api/twisted.web.client.getPage.html

The resulting code(insert your key, secret, username and password):

from oauth import oauth
from twisted.web.client import getPage
from twisted.internet import reactor
from twittytwister import twitter
import cgi

url = "https://api.twitter.com/oauth/access_token"
consumer = oauth.OAuthConsumer("key", "secret")

def respond(tokens):
    params = cgi.parse_qs(tokens, keep_blank_values=False)
    key = params['oauth_token'][0]
    secret = params['oauth_token_secret'][0]
    print "got access"

    token = oauth.OAuthToken(key, secret)
    tweet = twitter.Twitter(consumer=consumer, token=token).update("Hello world! First tweet using xauth via #Twisted and #Python")
    tweet.addCallback(posted)

def posted(message):
    print "message:", message

request = oauth.OAuthRequest.from_consumer_and_token(oauth_consumer=consumer, http_method='POST', http_url=url,
    parameters = {
        'x_auth_mode': 'client_auth',
        'x_auth_username': 'username',
        'x_auth_password': 'password'
    }
)
request.sign_request(oauth.OAuthSignatureMethod_HMAC_SHA1(), consumer, None)

page = getPage(url, method='POST', postdata=request.to_postdata())
page.addCallback(respond)

print "running..."
reactor.run()