2727import base64
2828import re
2929import requests
30- from requests_oauthlib import OAuth1
30+ from requests_oauthlib import OAuth1 , OAuth2
3131import io
3232import warnings
3333from 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