Skip to content
This repository was archived by the owner on Aug 7, 2024. It is now read-only.

Commit fa548ce

Browse files
authored
Merge pull request #423 from BarraQDA/master
Reworked @bryanlandia extension to allow application-only authentication
2 parents e02e9b8 + c71c197 commit fa548ce

1 file changed

Lines changed: 45 additions & 16 deletions

File tree

twitter/api.py

Lines changed: 45 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
import base64
2828
import re
2929
import requests
30-
from requests_oauthlib import OAuth1
30+
from requests_oauthlib import OAuth1, OAuth2
3131
import io
3232
import warnings
3333
from uuid import uuid4
@@ -144,6 +144,7 @@ def __init__(self,
144144
consumer_secret=None,
145145
access_token_key=None,
146146
access_token_secret=None,
147+
application_only_auth=False,
147148
input_encoding=None,
148149
request_headers=None,
149150
cache=DEFAULT_CACHE,
@@ -170,6 +171,9 @@ def __init__(self,
170171
access_token_secret (str):
171172
The oAuth access token's secret, also retrieved
172173
from the get_access_token.py run.
174+
application_only_auth:
175+
Use Application-Only Auth instead of User Auth.
176+
Defaults to False [Optional]
173177
input_encoding (str, optional):
174178
The encoding used to encode input strings.
175179
request_header (dict, optional):
@@ -259,16 +263,12 @@ def __init__(self,
259263
"strongly advised to increase it above 16384"
260264
))
261265

262-
if consumer_key is not None and (access_token_key is None or
263-
access_token_secret is None):
264-
print('Twitter now requires an oAuth Access Token for API calls. '
265-
'If you\'re using this library from a command line utility, '
266-
'please run the included get_access_token.py tool to '
267-
'generate one.', file=sys.stderr)
266+
if (consumer_key and not
267+
(application_only_auth or all([access_token_key, access_token_secret]))):
268+
raise TwitterError({'message': "Missing oAuth Consumer Key or Access Token"})
268269

269-
raise TwitterError({'message': "Twitter requires oAuth Access Token for all API access"})
270-
271-
self.SetCredentials(consumer_key, consumer_secret, access_token_key, access_token_secret)
270+
self.SetCredentials(consumer_key, consumer_secret, access_token_key, access_token_secret,
271+
application_only_auth)
272272

273273
if debugHTTP:
274274
import logging
@@ -282,11 +282,33 @@ def __init__(self,
282282
requests_log.setLevel(logging.DEBUG)
283283
requests_log.propagate = True
284284

285+
def GetAppOnlyAuthToken(self, consumer_key, consumer_secret):
286+
"""
287+
Generate a Bearer Token from consumer_key and consumer_secret
288+
"""
289+
from urllib import quote_plus
290+
import base64
291+
292+
key = quote_plus(consumer_key)
293+
secret = quote_plus(consumer_secret)
294+
bearer_token = base64.b64encode('{}:{}'.format(key, secret) )
295+
296+
post_headers = {
297+
'Authorization': 'Basic '+bearer_token,
298+
'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8'
299+
}
300+
res = requests.post(url='https://api.twitter.com/oauth2/token',
301+
data={'grant_type':'client_credentials'},
302+
headers=post_headers)
303+
bearer_creds = res.json()
304+
return bearer_creds
305+
285306
def SetCredentials(self,
286307
consumer_key,
287308
consumer_secret,
288309
access_token_key=None,
289-
access_token_secret=None):
310+
access_token_secret=None,
311+
application_only_auth=False):
290312
"""Set the consumer_key and consumer_secret for this instance
291313
292314
Args:
@@ -300,17 +322,23 @@ def SetCredentials(self,
300322
access_token_secret:
301323
The oAuth access token's secret, also retrieved
302324
from the get_access_token.py run.
325+
application_only_auth:
326+
Whether to generate a bearer token and use Application-Only Auth
303327
"""
304328
self._consumer_key = consumer_key
305329
self._consumer_secret = consumer_secret
306330
self._access_token_key = access_token_key
307331
self._access_token_secret = access_token_secret
308-
auth_list = [consumer_key, consumer_secret,
309-
access_token_key, access_token_secret]
310332

311-
if all(auth_list):
312-
self.__auth = OAuth1(consumer_key, consumer_secret,
313-
access_token_key, access_token_secret)
333+
if application_only_auth:
334+
self._bearer_token = self.GetAppOnlyAuthToken(consumer_key, consumer_secret)
335+
self.__auth = OAuth2(token=self._bearer_token)
336+
else:
337+
auth_list = [consumer_key, consumer_secret,
338+
access_token_key, access_token_secret]
339+
if all(auth_list):
340+
self.__auth = OAuth1(consumer_key, consumer_secret,
341+
access_token_key, access_token_secret)
314342

315343
self._config = None
316344

@@ -353,6 +381,7 @@ def ClearCredentials(self):
353381
self._consumer_secret = None
354382
self._access_token_key = None
355383
self._access_token_secret = None
384+
self._bearer_token = None
356385
self.__auth = None # for request upgrade
357386

358387
def GetSearch(self,

0 commit comments

Comments
 (0)