We're using Rauth to connect to various OAuth 1 APIs. It works fine for a single request, but trying to do 2 or more requests against the given session results in 401 not authorized errors from the APIs.
Twitter API example:
import requests
from rauth import OAuth1Service
from rauth import OAuth1Session
consumer_key = {the consumer key}
consumer_secret = {the consumer secret}
access_token = {the access token}
access_token_secret = {the access token secret}
oauth_service = OAuth1Service(consumer_key = consumer_key,
consumer_secret = consumer_secret)
oauth_session = oauth_service.get_session(token = (access_token, access_secret))
url = 'https://api.twitter.com/1.1/statuses/home_timeline.json'
params = {'include_rts': 'true'}
r = oauth_session.get(url, params=params) # THIS WORKS
r = oauth_session.get(url, params=params) # THIS RETURNS 401 ERROR
This happens on both Twitter and LinkedIn APIs. How do we execute multiple requests against a single OAuth1Session
object?
VERSIONS:
rauth==0.5.4
requests==1.1.0
Strangely, if the params
argument is not included then multiple requests can be made- but once params
are included, even if it is an empty dict, we get 401s.
Example 1:
r = oauth_session.get(url) # THIS WORKS
r = oauth_session.get(url) # THIS WORKS
Example 2:
r = oauth_session.get(url, params={}) # THIS WORKS
r = oauth_session.get(url, params={}) # THIS RETURNS 401 ERROR
Carrying over from the comments, using session.get(..., header_auth=True)
should do the trick. It's hard to say exactly why it doesn't work without this, but for the record, header-based authentication is preferred by the spec and given Twitter's position, I wouldn't be surprised if they also prefer it as a provider.
A quick search reveals dozens upon dozens of reports of their API failing where it ostensibly should work and one remedy is to prefer header authentication. From what I can tell, rauth is signing appropriately, so perhaps this is something to do with the way the provider is showing preference and handling non-header authenticated requests.
It looks like either rauth or Requests was not properly handling params. It's odd because the signature base string and oauth_signature
seemed to be correct, in that they were appropriately different on each respective request and the data they operated on seemed to checkout. So it seems like it should have validated the request.
At any rate, to correct this, we need to deepcopy elements of the request parameters that are mutable types, e.g. dictionaries. I've got a patch that should correct this, so you should be able to use this without header_auth
. However, header authentication is the preferred method so I would still recommend it.