]> jfr.im git - z_archive/twitter.git/commitdiff
Improve OAuth2 app-only code and documentation
authorMike Verdone <redacted>
Thu, 24 Jul 2014 22:39:28 +0000 (00:39 +0200)
committerMike Verdone <redacted>
Thu, 24 Jul 2014 22:39:28 +0000 (00:39 +0200)
twitter/__init__.py
twitter/oauth2.py
twitter/oauth_dance.py
twitter/stream_example.py

index 326c8f279841cb9b70f6aa545a36d5ca5f712b5c..d0d6507934a92d6d37cb3cd99e0c4aff55ebdd4b 100644 (file)
@@ -10,11 +10,14 @@ from textwrap import dedent
 
 from .api import Twitter, TwitterError, TwitterHTTPError, TwitterResponse
 from .auth import NoAuth, UserPassAuth
-from .oauth import (OAuth, read_token_file, write_token_file,
-                    __doc__ as oauth_doc)
-from .oauth2 import OAuth2
+from .oauth import (
+    OAuth, read_token_file, write_token_file,
+    __doc__ as oauth_doc)
+from .oauth2 import (
+    OAuth2, read_bearer_token_file, write_bearer_token_file,
+    __doc__ as oauth2_doc)
 from .stream import TwitterStream
-from .oauth_dance import oauth_dance
+from .oauth_dance import oauth_dance, oauth2_dance
 
 __doc__ = __doc__ or ""
 
@@ -43,9 +46,9 @@ Authentication
 --------------
 
 You can authenticate with Twitter in three ways: NoAuth, OAuth, or
-UserPassAuth. Get help() on these classes to learn how to use them.
+OAuth2 (app-only). Get help() on these classes to learn how to use them.
 
-OAuth is probably the most useful.
+OAuth and OAuth2 are probably the most useful.
 
 
 Working with OAuth
@@ -54,6 +57,27 @@ Working with OAuth
 
 __doc__ += dedent(oauth_doc or "")
 
-__all__ = ["Twitter", "TwitterStream", "TwitterResponse", "TwitterError",
-           "TwitterHTTPError", "NoAuth", "OAuth", "UserPassAuth",
-           "read_token_file", "write_token_file", "oauth_dance", "OAuth2"]
+__doc__ += """
+Working with OAuth2
+-------------------
+"""
+
+__doc__ += dedent(oauth2_doc or "")
+
+__all__ = [
+    "NoAuth",
+    "OAuth",
+    "OAuth2",
+    "oauth2_dance",
+    "oauth_dance",
+    "read_bearer_token_file",
+    "read_token_file",
+    "Twitter",
+    "TwitterError",
+    "TwitterHTTPError",
+    "TwitterResponse",
+    "TwitterStream",
+    "UserPassAuth",
+    "write_bearer_token_file",
+    "write_token_file",
+    ]
index a71bab125e050de540be5548e00a5156d4f0aab3..9b4d8466a676b28f37629391e40220c698ed4838 100644 (file)
@@ -1,17 +1,20 @@
 """
-Visit the Twitter developer page and create a new application:
+Twitter only supports the application-only flow of OAuth2 for certain
+API endpoints. This OAuth2 authenticator only supports the application-only
+flow right now.
+
+To authenticate with OAuth2, visit the Twitter developer page and create a new
+application:
 
     https://dev.twitter.com/apps/new
 
 This will get you a CONSUMER_KEY and CONSUMER_SECRET.
 
-Twitter only supports the application-only flow of OAuth2 for certain
-API endpoints. This OAuth2 authenticator only supports the application-only
-flow right now. If twitter supports OAuth2 for other endpoints, this
-authenticator may be modified as needed.
+Exchange your CONSUMER_KEY and CONSUMER_SECRET for a bearer token using the
+oauth2_dance function.
 
-Finally, you can use the OAuth2 authenticator to connect to Twitter. In
-code it all goes like this::
+Finally, you can use the OAuth2 authenticator and your bearer token to connect
+to Twitter. In code it goes like this::
 
     twitter = Twitter(auth=OAuth2(bearer_token=BEARER_TOKEN))
 
@@ -30,6 +33,20 @@ except ImportError:
 from base64 import b64encode
 from .auth import Auth
 
+def write_bearer_token_file(filename, oauth2_bearer_token):
+    """
+    Write a token file to hold the oauth2 bearer token.
+    """
+    oauth_file = open(filename, 'w')
+    print(oauth2_bearer_token, file=oauth_file)
+    oauth_file.close()
+
+def read_bearer_token_file(filename):
+    """
+    Read a token file and return the oauth2 bearer token.
+    """
+    f = open(filename)
+    return f.readline().strip()
 
 class OAuth2(Auth):
     """
@@ -42,22 +59,16 @@ class OAuth2(Auth):
         consumer_secret if you are requesting a bearer_token. Otherwise
         you must supply the bearer_token.
         """
-        self.bearer_token = None
-        self.consumer_key = None
-        self.consumer_secret = None
-
-        if bearer_token:
-            self.bearer_token = bearer_token
-        elif consumer_key and consumer_secret:
-            self.consumer_key = consumer_key
-            self.consumer_secret = consumer_secret
-        else:
+        self.bearer_token = bearer_token
+        self.consumer_key = consumer_key
+        self.consumer_secret = consumer_secret
+
+        if not (bearer_token or (consumer_key and consumer_secret)):
             raise MissingCredentialsError(
                 'You must supply either a bearer token, or both a '
                 'consumer_key and a consumer_secret.')
 
     def encode_params(self, base_url, method, params):
-
         return urlencode(params)
 
     def generate_headers(self):
@@ -66,25 +77,18 @@ class OAuth2(Auth):
                 b'Authorization': 'Bearer {0}'.format(
                     self.bearer_token).encode('utf8')
             }
-
-        elif self.consumer_key and self.consumer_secret:
-
+        else:
             headers = {
                 b'Content-Type': (b'application/x-www-form-urlencoded;'
                                   b'charset=UTF-8'),
-                b'Authorization': 'Basic {0}'.format(
-                    b64encode('{0}:{1}'.format(
+                b'Authorization': 'Basic {}'.format(
+                    b64encode('{}:{}'.format(
                         quote(self.consumer_key),
                         quote(self.consumer_secret)).encode('utf8')
                     ).decode('utf8')
                 ).encode('utf8')
             }
-
-        else:
-            raise MissingCredentialsError(
-                'You must supply either a bearer token, or both a '
-                'consumer_key and a consumer_secret.')
-
+        print(headers)
         return headers
 
 
index d3f0ea8f6548635a5c93d6c832f160bb0d5f5cf3..1e398496cabbd55d6038e8cf7ca63af1bff184ad 100644 (file)
@@ -2,9 +2,11 @@ from __future__ import print_function
 
 import webbrowser
 import time
+import json
 
-from .api import Twitter
+from .api import Twitter, json
 from .oauth import OAuth, write_token_file
+from .oauth2 import OAuth2, write_bearer_token_file
 
 try:
     _input = raw_input
@@ -12,6 +14,23 @@ except NameError:
     _input = input
 
 
+def oauth2_dance(consumer_key, consumer_secret, token_filename=None):
+    """
+    Perform the OAuth2 dance to transform a consumer key and secret into a
+    bearer token.
+
+    If a token_filename is given, the bearer token will be written to
+    the file.
+    """
+    twitter = Twitter(
+        auth=OAuth2(consumer_key=consumer_key, consumer_secret=consumer_secret),
+        format="",
+        api_version="")
+    token = json.loads(twitter.oauth2.token(grant_type="client_credentials")
+        .encode("utf8"))["access_token"]
+    if token_filename:
+        write_bearer_token_file(token)
+    return token
 
 def oauth_dance(app_name, consumer_key, consumer_secret, token_filename=None):
     """
index 8869c15f8515adec138e35f5f1b7ce01b46009d7..4e5184c335520c9ab1cfa7819a6d83f3470ab172 100644 (file)
@@ -9,9 +9,9 @@ import argparse
 
 from twitter.stream import TwitterStream, Timeout, HeartbeatTimeout, Hangup
 from twitter.oauth import OAuth
+from twitter.oauth2 import OAuth2, read_bearer_token_file
 from twitter.util import printNicely
 
-
 def parse_arguments():
 
     parser = argparse.ArgumentParser(description=__doc__ or "")