Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unable to get OAuth "Request Token" while working with the Tumblr API using Python

I've been using libraries to handle OAuth so far, but lately I've been digging deeper trying to understand the underlying OAuth process. Currently, I'm trying to connect to Tumblr API v2 using OAuth 1.0a with this simple code:

import urllib, urllib2, time, random, hmac, base64, hashlib

def makenonce():
    random_number = ''.join( str( random.randint( 0, 9 ) ) for _ in range( 40 ) )
    m = hashlib.md5( str( time.time() ) + str( random_number ) )
    return m.hexdigest()

def encodeparams(s):
    return urllib.quote( str( s ), safe='~' )

# Actual key and secret from a test app created using a dummy Tumblr account
consumer_key = '97oAujQhSaQNv4XDXzCjdZlOxwNyhobmDwmueJBCHWsFFsW7Ly'
consumer_secret = '5q1dpF659SOgSUb0Eo52aAyoud8N8QOuJu6enCG92aDR6WoMlf'

#oauth URLs
request_tokenURL = 'http://www.tumblr.com/oauth/request_token'

#oauth params
oauth_parameters = {
            'oauth_consumer_key'     : consumer_key,
            'oauth_nonce'            : makenonce(),
            'oauth_timestamp'        : str(int(time.time())),
            'oauth_signature_method' : "HMAC-SHA1",
            'oauth_version'          : "1.0"
            }

normalized_parameters = encodeparams( '&'.join( ['%s=%s' % ( encodeparams( str( k ) ), encodeparams( str( oauth_parameters[k] ) ) ) for k in sorted( oauth_parameters )] ) )
# Since I'm focusing only on getting the request token for now, I set this to POST.
normalized_http_method = 'POST'
normalized_http_url = encodeparams( request_tokenURL )
signature_base_string = '&'.join( [normalized_http_method, normalized_http_url, normalized_parameters] )
oauth_key = consumer_secret + '&'
hashed = hmac.new( oauth_key, signature_base_string, hashlib.sha1 )
oauth_parameters['oauth_signature'] = base64.b64encode( hashed.digest() )
oauth_header = 'Authorization: OAuth realm="http://www.tumblr.com",' + 'oauth_nonce="' + oauth_parameters['oauth_nonce'] + '",' + 'oauth_timestamp="' + oauth_parameters['oauth_timestamp'] + '",' + 'oauth_consumer_key="' + oauth_parameters['oauth_consumer_key'] + '",' + 'oauth_signature_method="HMAC-SHA1",oauth_version="1.0",oauth_signature="' + oauth_parameters['oauth_signature'] +'"'

# sample oauth_header generated by the code above:
# Authorization: OAuth realm="http://www.tumblr.com",oauth_nonce="c200a0e06f30b84b851ac3e99a71054b",oauth_timestamp="1315231855",oauth_consumer_key="97oAujQhSaQNv4XDXzCjdZlOxwNyhobmDwmueJBCHWsFFsW7Ly",oauth_signature_method="HMAC-SHA1",oauth_version="1.0",oauth_signature="kVAlmwolCX0WJIvTF9MB2UV5rnU="


req = urllib2.Request( request_tokenURL )
req.add_header( 'Authorization', oauth_header )
# If all goes well, Tumblr should send me the oauth request token.
print urllib2.urlopen( req ).read()

Instead of the OAuth Request token, Tumblr returns HTTP Error 401: Unauthorized.

Things I've tried without any success:

  1. Changed oauth_version from "1.0" to "1.0a", and changed it back again.
  2. A guide on OAuth mandated adding the '&' at the end of consumer_secret to get the oauth_key. I tried removing the '&' later to see if that made any difference.
  3. Checked if the OAuth parameters were sorted, and they were.
  4. Did not add the string "Authorization: " to oauth_header, then added it back later. Neither made any difference.

Where have I gone wrong?

like image 872
vjk2005 Avatar asked Oct 10 '22 02:10

vjk2005


1 Answers

Solved it after making just 2 simple changes in the above code:

  1. normalized_http_method = 'GET' #not POST
  2. oauth_header = 'OAuth realm="http://www...' # The word "Authorization" is unnecessary. I had taken this out earlier as listed in "Things I've tried without any success", but the error listed in (1) threw me off track. With (1) solved, I could see how "Authorization" was indeed unnecessary.

The OAuth Request token Tumblr sent me when I finally got it right: oauth_token=mbRUgyDkPePfkEztiLELMqUl1kyNXEcaTCCwpb7SoXDF9mhiTF&oauth_token_secret=5pXllXGKA8orAaUat1G7ckIfMfYup8juMBAgEELUkeMZoC3pv6&oauth_callback_confirmed=true

This is a one-time only token and I've listed it here just for the sake of completeness.

like image 188
vjk2005 Avatar answered Oct 26 '22 00:10

vjk2005