How To Build a Twitter "Hello World" Web App in Python

Sending a Request

Sending a request is split into two tasks: getting OAuth tokens and sending a REST API request. Our sample application includes the following features:

  • Shows the last 20 tweets for a given user. Since a login is not required to show tweets, this feature will depend on the Twitter’s OAuth 2.0-based Application-only authorization.
  • Sends a tweet to one of the users mentioned in the last 20 tweets based on user interaction. Since sending a tweet requires that the application be logged-in on behalf of the user, this feature will depend on Twitter’s OAuth 1.0a-based 3-legged authorization

Note that the code shown is intended to be informative rather than normative; error handling and the like are excluded for the sake of brevity. 

Application-only authorization

Implementing an Oauth 2.0-based application-only authorization with Twitter is a fairly straightforward task. Firstly, the application must hit the /oauth2/token endpoint with a payload of grant_type=client_credentials to obtain an access token, passing the Consumer Key and Consumer Secret as the equivalent of username and password in a HTTP Basic Authorization header:

import urllib3, json, base64

# Create a HTTP connection pool manager
manager = urllib3.PoolManager()

# Set the variable to Twitter OAuth 2 endpoint
oauth_url = 'https://api.twitter.com/oauth2/token' 

# Set the HTTP request headers, including consumer key and secret
http_headers={'Authorization': "Basic %s" % base64.b64encode("%s:%s" % (CONSUMER_KEY,CONSUMER_SECRET)), 'Content-Type': 'application/x-www-form-urlencoded'} 

# Set the payload to the required OAuth grant type, in this case client credentials
request_body="grant_type=client_credentials" 

# Send the request
response = manager.urlopen("POST", oauth_url, headers=http_headers, body=request_body)

# Read the response as JSON
app_token = json.loads(response.data) 

If the request is successful, the response body will be a JSON object containing an access token which grants access to public objects in the Twitter API:

{"token_type": "bearer", "access_token": "AAAAAAAAAAAAAAAAAAAAAN0SfwAAAAAAGdkpOHHSnP1x5c5IHl2j8khdl4k%3DyPIFwPj8iJ3vIpJ2d9RI5f7t0b9cV25SqHB1pmfOczQcupppsq"}

To read Tweets from a Twitter user’s timeline, this access token must be passed with an HTTP Authorization header of the type “Bearer”. The example code below requests the timeline for the Twitter handle “ProgrammableWeb”, which requires an application-only token to retrieve it and is used to populate the contents of a table that's displayed in the example Web application built for this tutorial.

​# Set the variable to the ProgrammableWeb timeline
url='https://api.twitter.com/1.1/statuses/user_timeline.json?screen_name=ProgrammableWeb'

# Set the Authorization header using the value of the access_token key from the app_token dictionary created above
http_headers={'Authorization': 'Bearer %s' % app_token ['access_token']}) 

# Send the request
response = manager.urlopen('GET', url , headers=http_header) 

# Read the response, create dictionary and render HTML using data and template
return render_template('timeline.html',tweets=json.loads(response.data))

In our sample application the data was rendered in a "Tweet list", that shows the last 20 tweets made by @ProgrammableWeb with a link to each user mentioned to initiate sending a tweet mentioning them:

Application-user Authorization

Implementing the application-user authorization flow is more complicated, but can still be accomplished with relatively little code. Typically, a 3-legged OAuth workflow starts when the third party application retrieves a special OAuth token called the “request token.”  The flow is then redirected to the end-user who is presented with a request to authorize the application for interaction with the service (Twitter in this case) on his or her behalf. Once the end-user authorizes the third-party application to access the service on his or her behalf, the workflow presents the previously obtained request token in order to secure an OAuth access token. The third-party application then uses that access token instead of a user ID and password to authenticate with the service (again, Twitter) on behalf of the end-user.

The first step is therefore to acquire a request token:

# Import required packages, including the oauthlib package discussed earlier in the tutorial
import oauth2, urlparse, flask, hmac, hashlib, urllib, urllib3

# Set the consumer key and secret
CONSUMER_KEY="YOUR CONSUMER KEY"
CONSUMER_SECRET="YOUR CONSUMER SECRET"

# Create a oauth2.Consumer object that wraps the parameters for the calls to the HTTP endpoints
consumer = oauth2.Consumer(CONSUMER_KEY, CONSUMER_SECRET)

# Use the oauth2.Client class to call the Twitter OAuth endpoint 
resp, content = oauth2.Client(consumer).request('https://api.twitter.com/oauth/request_token', "GET")

# Create a standard dictionary from the response body, using parse_qsl as a convenience to parse the query string in the response
request_token = dict(urlparse.parse_qsl(content))

​Once the request token has been obtained and loaded into a variable the application has the correct entitlement to complete the application-user authorization by redirecting the user to the Twitter authorization page:

# Redirect user to authorization page, encapsulating request token in URL
return flask.redirect("%s?oauth_token=%s" % ('https://api.twitter.com/oauth/authorize', request_token['oauth_token']))

Where the user will be presented with a form requesting their authorization for the application to access the required settings in profile:

On clicking "Authorize" the user will be redirected to the callback URL, where the application will retrieve an access token from Twitter before redirecting the user appropriately:

# Use oauthlib to wrap the tokens and set the oauth_verifier HTTP header
token = oauth2.Token(request_token['oauth_token'], request_token['oauth_token_secret'])
token.set_verifier(flask.request.args.get('oauth_verifier'))

# Create a new oauth2.Client object, wrapping both the consumer and token objects
client = oauth2.Client(consumer, token)

# Call the Twitter access token endpoint
resp, content = client.request('https://api.twitter.com/oauth/access_token', "POST")

# Create a standard dictionary from the response body, using parse_qsl as a convenience to parse the query string in the response
access_token = dict(urlparse.parse_qsl(content))

​With the access token for the given user in hand, the application can now sign requests that read or write data on a users behalf; in order to do this, an application must generate an OAuth 1.0a HMAC-SHA1 signature for the HTTP request, which is implemented as a security measure to prevent unauthorized applications from making requests. The code snippet below shows all of the parameters that Twitter requires and uses the the previously acquired access tokens to send a tweet on behalf of the authorized user (Twitter provides detailed guidance on implementing this functionality):

screen_name='programmableweb'
url='https://api.twitter.com/1.1/statuses/update.json'
status="Hello World @%s!" % screen_name
manager = urllib3.PoolManager()

# Set the parameters required to build the base of the signature, using a dictionary for convenience
parameters = {
    "oauth_consumer_key": CONSUMER_KEY,
    "oauth_nonce":  hashlib.sha1(str(random.random)).hexdigest(),
    "oauth_signature_method": "HMAC-SHA1",
    "oauth_timestamp": str(int(time.time())),
    "oauth_token": access_token['oauth_token'],
    "oauth_version": "1.0",
    "status": status
}

# Build the string that forms the base of the signature, iterating through the dictionary and using the key/values in the string
base_string = "%s&%s&%s" % (method,urllib.quote(url,""),urllib.quote('&'.join(sorted("%s=%s" % (key,value)
                for key,value in parameters.iteritems())),""))

# Create the signature using signing key composed of consumer secret and token secret obtained during 3-legged dance
signature = hmac.hmac.new("%s&%s" % (urllib.quote(CONSUMER_SECRET,""),urllib.quote(access_token['oauth_token_secret'],"")),
                base_string,hashlib.sha1)

# Add result to parameters and create a string in required format for header
parameters['oauth_signature'] = signature.digest().encode("base64").rstrip('\n')
auth_header = 'OAuth %s' % ', '.join(sorted('%s="%s"' % (urllib.quote(key,""),urllib.quote(value,""))
                for key,value in parameters.iteritems() if key != 'status'))

# Set HTTP headers                
http_headers={"Authorization": auth_header, 'Content-Type': 'application/x-www-form-urlencoded'}

# Send the request
response = manager.urlopen("POST", url, headers=headers,body=status)

# Set messages that will be used in modal dialogs
if response.status == 200:
    flask.flash("Tweet sent mentioning @%s" % screen_name)
else:
    flask.flash("Error sending tweet: %s" % response.data)

​Our web application presents the user with a form allowing them to tweet to one of the mentioned users. On clicking the "Tweet" button the tweet is submitted and a dialog show confirming the result (based on the flash message shown in the code snippet).
Sample application - Tweet form
And the tweet is sent (note that the mentioned user was edited before sending the tweet!):
Sample application - Tweet sent

Summary

This tutorial shows the ease with which a web application can be created in Python that integrates with the Twitter API. The walkthrough is not designed to implement any stunning functionality but to show the linkages between application metadata in the developer center, the OAuth implementation and the authorization required to implement particular types of functionality. Hopefully, when armed with this knowledge a developer will have all the facilities at their disposal to create their own imaginative Twitter integrations.

Chris Wood Chris is a freelance API specialist. His main interests are API management, Python and doing interesting stuff. Connect with Chris on Twitter

Comments

Comments(9)

aforajay79

Hi, I have the consumer key and secret and would like to get access token and secret without manual intervention of user. In your code the user is directed to url and he has to manually grant access. Is there any way to code just to get token without the 3-way manual dance. For example i provide the consumer key and secret and i get back access token.

cwwood1975

Morning. Unfortunately if your application needs to perform an action on behalf of a user you are obliged to use the 3-legged OAuth dance unless you are accesses your data from your account (see here for single user authorization: https://dev.twitter.com/oauth/overview/single-user). This link https://dev.twitter.com/oauth/overview shows the type of authorization required for given scenarios.

You could always fudge this of course, but that kind of depends on having access to the user name and password of the user you are doing something on behalf and using something like Selenium to respond to the Twitter prompts like you are in a browser. Not hard but also not for the faint hearted.

Good luck!

kabal

Hi, this is very useful, however when I implement it twitter responds with a key that I have to provide to the App. I guess the problem is that I am not providing a callback URL, how do I say so? You say that twitter should redirect to that callback URL, but I don't see anywhere in the code where that URL is provided. Thanks in advance

kabal

Hi!, very useful post, thanks you very much. I am having a problem following it, once I authorize twitter I am getting a PIN that should be provided to the App. I guess this is because I did not provide a callback URL, however I don't see anywhere in your code where this callback is provided. Thank you very much

cwwood1975

Hello and thanks for your question.

You've pulled the GitHub repo I provided in the comments above? https://github.com/SensibleWood/TwitterTutorial

This is a working solution that you 'should' be able to run (once you've got the required packages install). The callback URL is dealt with by the following Flask route:

@app.route("/callback")

def handle_callback():

    global ACCESS_TOKEN

    ....

For this Flask app to work correctly your application config on Twitter will need to know about the callback URL to redirect the user.

kabal

Hi thanks, yeah I got the files from the GitHub repo, but twitter just displays a PIN which I am supposed to use to authorize my App. Anyway I got it to work using that PIN to authorize the App and then I receive a token. The problem is that the flow is kind of awkward for the user, because he needs to go back to the App and type that PIN. I still don't see how is twitter supposed to know what the URL for the callback URL is. I thought I was supposed to send that information to the twitter API when I call https://api.twitter.com/oauth/request_token. I actually tried to add a parameter oauth_callback as explained in  https://dev.twitter.com/oauth/reference/post/oauth/request_token, but that didn't work. Anyway, again, this post has been really useful for me.

PD: ok sorry, I just read the last sentence "For this Flask app to work correctly your application config on Twitter will need to know about the callback URL to redirect the user". I guess I will try that, thanks.

 

  

kabal

Ok, it did work, thank you very much. I just configured my callback URL in my twitter account, I was trying to specify the callback URL in the call to the API. It's weird that on twitter it says: "oauth 1.0a applications should explicitly specify their oauth_callback URL on the request token step, regardless of the value given here", but it works although I am not providing it. Thanks again

cwwood1975

Yes, I'd say that's what you'd call a 'feature' of the Twitter REST API. Still, glad it's now working for you. :0)