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
@@ -146,6 +146,7 @@ def __init__(self,
146146 consumer_secret = None ,
147147 access_token_key = None ,
148148 access_token_secret = None ,
149+ application_only_auth = False ,
149150 input_encoding = None ,
150151 request_headers = None ,
151152 cache = DEFAULT_CACHE ,
@@ -171,6 +172,9 @@ def __init__(self,
171172 access_token_secret (str):
172173 The oAuth access token's secret, also retrieved
173174 from the get_access_token.py run.
175+ application_only_auth:
176+ Use Application-Only Auth instead of User Auth.
177+ Defaults to False [Optional]
174178 input_encoding (str, optional):
175179 The encoding used to encode input strings.
176180 request_header (dict, optional):
@@ -256,16 +260,13 @@ def __init__(self,
256260 "strongly advised to increase it above 16384"
257261 ))
258262
259- if consumer_key is not None and (access_token_key is None or
260- access_token_secret is None ):
261- print ('Twitter now requires an oAuth Access Token for API calls. '
262- 'If you\' re using this library from a command line utility, '
263- 'please run the included get_access_token.py tool to '
264- 'generate one.' , file = sys .stderr )
263+ if consumer_key is None or consumer_secret is None or (
264+ not application_only_auth
265+ and (access_token_key is None or access_token_secret is None )):
266+ raise TwitterError ({'message' : "Missing oAuth Consumer Key or Access Token" })
265267
266- raise TwitterError ({'message' : "Twitter requires oAuth Access Token for all API access" })
267-
268- self .SetCredentials (consumer_key , consumer_secret , access_token_key , access_token_secret )
268+ self .SetCredentials (consumer_key , consumer_secret , access_token_key , access_token_secret ,
269+ application_only_auth )
269270
270271 if debugHTTP :
271272 import logging
@@ -279,11 +280,33 @@ def __init__(self,
279280 requests_log .setLevel (logging .DEBUG )
280281 requests_log .propagate = True
281282
283+ def GetAppOnlyAuthToken (self , consumer_key , consumer_secret ):
284+ """
285+ Generate a Bearer Token from consumer_key and consumer_secret
286+ """
287+ from urllib import quote_plus
288+ import base64
289+
290+ key = quote_plus (consumer_key )
291+ secret = quote_plus (consumer_secret )
292+ bearer_token = base64 .b64encode ('{}:{}' .format (key , secret ) )
293+
294+ post_headers = {
295+ 'Authorization' : 'Basic ' + bearer_token ,
296+ 'Content-Type' : 'application/x-www-form-urlencoded;charset=UTF-8'
297+ }
298+ res = requests .post (url = 'https://api.twitter.com/oauth2/token' ,
299+ data = {'grant_type' :'client_credentials' },
300+ headers = post_headers )
301+ bearer_creds = res .json ()
302+ return bearer_creds
303+
282304 def SetCredentials (self ,
283305 consumer_key ,
284306 consumer_secret ,
285307 access_token_key = None ,
286- access_token_secret = None ):
308+ access_token_secret = None ,
309+ application_only_auth = False ):
287310 """Set the consumer_key and consumer_secret for this instance
288311
289312 Args:
@@ -297,17 +320,23 @@ def SetCredentials(self,
297320 access_token_secret:
298321 The oAuth access token's secret, also retrieved
299322 from the get_access_token.py run.
323+ application_only_auth:
324+ Whether to generate a bearer token and use Application-Only Auth
300325 """
301326 self ._consumer_key = consumer_key
302327 self ._consumer_secret = consumer_secret
303328 self ._access_token_key = access_token_key
304329 self ._access_token_secret = access_token_secret
305- auth_list = [consumer_key , consumer_secret ,
306- access_token_key , access_token_secret ]
307330
308- if all (auth_list ):
309- self .__auth = OAuth1 (consumer_key , consumer_secret ,
310- access_token_key , access_token_secret )
331+ if application_only_auth :
332+ self ._bearer_token = self .GetAppOnlyAuthToken (consumer_key , consumer_secret )
333+ self .__auth = OAuth2 (token = self ._bearer_token )
334+ else :
335+ auth_list = [consumer_key , consumer_secret ,
336+ access_token_key , access_token_secret ]
337+ if all (auth_list ):
338+ self .__auth = OAuth1 (consumer_key , consumer_secret ,
339+ access_token_key , access_token_secret )
311340
312341 self ._config = None
313342
@@ -350,6 +379,7 @@ def ClearCredentials(self):
350379 self ._consumer_secret = None
351380 self ._access_token_key = None
352381 self ._access_token_secret = None
382+ self ._bearer_token = None
353383 self .__auth = None # for request upgrade
354384
355385 def GetSearch (self ,
0 commit comments