I have the following implementation of a twitter
client using rauth
(OAuth1
), based on the twitter-timeline-cli.py
script in the rauth examples:
from rauth.service import OAuth1Service
class TwitterClient:
KNOWN_USERS = {
'user1' : ("xxx", "yyy", "2342354"), # These should be real tokens
}
def __init__(self):
# Get a real consumer key & secret from https://dev.twitter.com/apps/new
self.twitter = OAuth1Service(
name='twitter',
consumer_key=TWITTER_CONSUMER_KEY,
consumer_secret=TWITTER_CONSUMER_SECRET,
request_token_url='https://api.twitter.com/oauth/request_token',
access_token_url='https://api.twitter.com/oauth/access_token',
authorize_url='https://api.twitter.com/oauth/authorize',
base_url='https://api.twitter.com/1/')
def authorize(self):
request_token, request_token_secret = self.twitter.get_request_token()
authorize_url = self.twitter.get_authorize_url(request_token)
print 'Visit this URL in your browser: ' + authorize_url
pin = raw_input('Enter PIN from browser: ')
return request_token, request_token_secret, pin
def init_session(self, user):
if user in self.KNOWN_USERS :
request_token, request_token_secret, pin = self.KNOWN_USERS[user]
else:
request_token, request_token_secret, pin = self.authorize()
session = self.twitter.get_auth_session(request_token,
request_token_secret,
method='POST',
data={'oauth_verifier': pin})
return session
def list_tweets(self, user):
session = self.init_session(user)
params = {'include_rts': 1, # Include retweets
'count': 10} # 10 tweets
r = session.get('statuses/home_timeline.json', params=params)
for i, tweet in enumerate(r.json(), 1):
handle = tweet['user']['screen_name'].encode('utf-8')
text = tweet['text'].encode('utf-8')
print '{0}. @{1} - {2}'.format(i, handle, text)
tc = TwitterClient()
tc.list_tweets('user1')
The idea is that, if the user is not known, he is requested to authorize the application. If, on the other hand, the user has already authorized this application, the authorization tokens (request_token, request_token_secret, pin) should be reused (normally the tokens would be in a database; for the time being, they are hard-coded in the script)
But this is not working:
Traceback (most recent call last):
File "my-twitter-timeline-cli.py", line 56, in <module>
tc.list_tweets('user1')
File "my-twitter-timeline-cli.py", line 43, in list_tweets
session = self.init_session(user)
File "my-twitter-timeline-cli.py", line 39, in init_session
data={'oauth_verifier': pin})
File ".../lib/python2.7/site-packages/rauth/service.py", line 326, in get_auth_session
**kwargs)
File ".../lib/python2.7/site-packages/rauth/service.py", line 299, in get_access_token
process_token_request(r, decoder, key_token, key_token_secret)
File ".../lib/python2.7/site-packages/rauth/service.py", line 25, in process_token_request
raise KeyError(PROCESS_TOKEN_ERROR.format(key=bad_key, raw=r.content))
KeyError: 'Decoder failed to handle oauth_token with data as returned by provider. A different decoder may be needed. Provider returned: <?xml version="1.0" encoding="UTF-8"?>\n<hash>\n <error>Invalid / expired Token</error>\n <request>/oauth/access_token</request>\n</hash>\n'
Is it possible to reuse OAuth1
authorization tokens?
I was misunderstanding the whole process. We do not need to save the request_token
, request_token_secret
and pin
, but the access_token
and the access_token_secret
.
The process is actually:
request_token
, request_token_secret
and pin
to get access_token
and access_token_secret
access_token
and access_token_secret
(to database, or whatever)access_token
and access_token_secret
This is my corrected test code:
from rauth.service import OAuth1Service
class TwitterClient:
KNOWN_USERS = { # (access_token, access_token_secret)
'user1' : ("xxx", "yyy")
}
def __init__(self):
# Get a real consumer key & secret from https://dev.twitter.com/apps/new
self.twitter = OAuth1Service(
name='twitter',
consumer_key=TWITTER_CONSUMER_KEY,
consumer_secret=TWITTER_CONSUMER_SECRET,
request_token_url='https://api.twitter.com/oauth/request_token',
access_token_url='https://api.twitter.com/oauth/access_token',
authorize_url='https://api.twitter.com/oauth/authorize',
base_url='https://api.twitter.com/1/')
def new_session(self):
request_token, request_token_secret = self.twitter.get_request_token()
authorize_url = self.twitter.get_authorize_url(request_token)
print 'Visit this URL in your browser: ' + authorize_url
pin = raw_input('Enter PIN from browser: ')
session = self.twitter.get_auth_session(request_token,
request_token_secret,
method='POST',
data={'oauth_verifier': pin})
print session.access_token, session.access_token_secret # Save this to database
return session
def reuse_session(self, user):
access_token, access_token_secret = self.KNOWN_USERS[user]
session = self.twitter.get_session((access_token, access_token_secret))
return session
def init_session(self, user):
if user in self.KNOWN_USERS : session = self.reuse_session(user)
else : session = self.new_session()
return session
def list_tweets(self, user):
session = self.init_session(user)
params = {'include_rts': 1, # Include retweets
'count': 10} # 10 tweets
r = session.get('statuses/home_timeline.json', params=params)
for i, tweet in enumerate(r.json(), 1):
handle = tweet['user']['screen_name'].encode('utf-8')
text = tweet['text'].encode('utf-8')
print '{0}. @{1} - {2}'.format(i, handle, text)
tc = TwitterClient()
tc.list_tweets('user1')