Update and improve authentication documentation
authorHarmon <Harmon758@gmail.com>
Sat, 8 Jan 2022 00:15:50 +0000 (18:15 -0600)
committerHarmon <Harmon758@gmail.com>
Sat, 8 Jan 2022 00:19:27 +0000 (18:19 -0600)
docs/auth_tutorial.rst [deleted file]
docs/authentication.rst [new file with mode: 0644]
docs/conf.py
docs/getting_started.rst
docs/index.rst
tweepy/auth.py

diff --git a/docs/auth_tutorial.rst b/docs/auth_tutorial.rst
deleted file mode 100644 (file)
index 8a22a61..0000000
+++ /dev/null
@@ -1,148 +0,0 @@
-.. _auth_tutorial:
-
-
-***********************
-Authentication Tutorial
-***********************
-
-Introduction
-============
-
-Tweepy supports both OAuth 1a (application-user) and OAuth 2
-(application-only) authentication. Authentication is handled by the
-tweepy.AuthHandler class.
-
-OAuth 1a Authentication
-=======================
-
-Tweepy tries to make OAuth 1a as painless as possible for you. To begin
-the process we need to register our client application with
-Twitter. Create a new application and once you
-are done you should have your consumer key and secret. Keep these
-two handy, you'll need them.
-
-The next step is creating an OAuthHandler instance. Into this we pass
-our consumer key and secret which was given to us in the previous
-paragraph::
-
-   auth = tweepy.OAuthHandler(consumer_key, consumer_secret)
-
-If you have a web application and are using a callback URL that needs
-to be supplied dynamically you would pass it in like so::
-
-   auth = tweepy.OAuthHandler(consumer_key, consumer_secret,
-   callback_url)
-
-If the callback URL will not be changing, it is best to just configure
-it statically on twitter.com when setting up your application's
-profile.
-
-Unlike basic auth, we must do the OAuth 1a "dance" before we can start
-using the API. We must complete the following steps:
-
-#. Get a request token from twitter
-
-#. Redirect user to twitter.com to authorize our application
-
-#. If using a callback, twitter will redirect the user to
-   us. Otherwise the user must manually supply us with the verifier
-   code.
-
-#. Exchange the authorized request token for an access token.
-
-So let's fetch our request token to begin the dance::
-
-   try:
-       redirect_url = auth.get_authorization_url()
-   except tweepy.TweepError:
-       print('Error! Failed to get request token.')
-
-This call requests the token from twitter and returns to us the
-authorization URL where the user must be redirect to authorize us. Now
-if this is a desktop application we can just hang onto our
-OAuthHandler instance until the user returns back. In a web
-application we will be using a callback request. So we must store the
-request token in the session since we will need it inside the callback
-URL request. Here is a pseudo example of storing the request token in
-a session::
-
-   session.set('request_token', auth.request_token['oauth_token'])
-
-So now we can redirect the user to the URL returned to us earlier from
-the get_authorization_url() method.
-
-If this is a desktop application (or any application not using
-callbacks) we must query the user for the "verifier code" that twitter
-will supply them after they authorize us. Inside a web application
-this verifier value will be supplied in the callback request from
-twitter as a GET query parameter in the URL.
-
-.. code-block :: python
-
-   # Example using callback (web app)
-   verifier = request.GET.get('oauth_verifier')
-
-   # Example w/o callback (desktop)
-   verifier = raw_input('Verifier:')
-
-The final step is exchanging the request token for an access
-token. The access token is the "key" for opening the Twitter API
-treasure box. To fetch this token we do the following::
-
-   # Let's say this is a web app, so we need to re-build the auth handler
-   # first...
-   auth = tweepy.OAuthHandler(consumer_key, consumer_secret)
-   token = session.get('request_token')
-   session.delete('request_token')
-   auth.request_token = { 'oauth_token' : token,
-                            'oauth_token_secret' : verifier }
-
-   try:
-       auth.get_access_token(verifier)
-   except tweepy.TweepError:
-       print('Error! Failed to get access token.')
-
-It is a good idea to save the access token for later use. You do not
-need to re-fetch it each time. Twitter currently does not expire the
-tokens, so the only time it would ever go invalid is if the user
-revokes our application access. To store the access token depends on
-your application. Basically you need to store 2 string values: key and
-secret::
-
-   auth.access_token
-   auth.access_token_secret
-
-You can throw these into a database, file, or where ever you store
-your data. To re-build an OAuthHandler from this stored access token
-you would do this::
-
-   auth = tweepy.OAuthHandler(consumer_key, consumer_secret)
-   auth.set_access_token(key, secret)
-
-So now that we have our OAuthHandler equipped with an access token, we
-are ready for business::
-
-   api = tweepy.API(auth)
-   api.update_status('tweepy + oauth!')
-
-OAuth 2 Authentication
-======================
-
-Tweepy also supports OAuth 2 authentication. OAuth 2 is a method of
-authentication where an application makes API requests without the
-user context. Use this method if you just need read-only access to
-public information.
-
-Like OAuth 1a, we first register our client application and acquire
-a consumer key and secret.
-
-Then we create an AppAuthHandler instance, passing in our consumer
-key and secret::
-
-   auth = tweepy.AppAuthHandler(consumer_key, consumer_secret)
-
-With the bearer token received, we are now ready for business::
-
-   api = tweepy.API(auth)
-   for tweet in tweepy.Cursor(api.search_tweets, q='tweepy').items(10):
-       print(tweet.text)
\ No newline at end of file
diff --git a/docs/authentication.rst b/docs/authentication.rst
new file mode 100644 (file)
index 0000000..383bae1
--- /dev/null
@@ -0,0 +1,301 @@
+.. _authentication:
+
+.. currentmodule:: tweepy
+
+**************
+Authentication
+**************
+
+This supplements Twitter's `Authentication documentation`_.
+
+.. _Authentication documentation: https://developer.twitter.com/en/docs/authentication/overview
+
+Introduction
+============
+
+Tweepy supports the OAuth 1.0a User Context, OAuth 2.0 Bearer Token (App-Only),
+and OAuth 2.0 Authorization Code Flow with PKCE (User Context) authentication
+methods.
+
+Twitter API v1.1
+================
+
+OAuth 2.0 Bearer Token (App-Only)
+---------------------------------
+The simplest way to generate a bearer token is through your app's Keys and
+Tokens tab under the `Twitter Developer Portal Projects & Apps page`_.
+
+.. _Twitter Developer Portal Projects & Apps page: https://developer.twitter.com/en/portal/projects-and-apps
+
+You can then initialize :class:`OAuth2BearerHandler` with the bearer token and
+initialize :class:`API` with the :class:`OAuth2BearerHandler` instance::
+
+    import tweepy
+
+    auth = tweepy.OAuth2BearerHandler("Bearer Token here")
+    api = tweepy.API(auth)
+
+Alternatively, you can use the API / Consumer key and secret that can be found
+on the same page and initialize :class:`OAuth2AppHandler` instead::
+
+    import tweepy
+
+    auth = tweepy.OAuth2AppHandler(
+        "API / Consumer Key here", "API / Consumer Secret here"
+    )
+    api = tweepy.API(auth)
+
+OAuth 1.0a User Context
+-----------------------
+Similarly, the simplest way to authenticate as your developer account is to
+generate an access token and access token secret through your app's Keys and
+Tokens tab under the `Twitter Developer Portal Projects & Apps page`_.
+
+You'll also need the app's API / consumer key and secret that can be found on
+that page.
+
+You can then initialize :class:`OAuth1UserHandler` with all four credentials
+and initialize :class:`API` with the :class:`OAuth1UserHandler` instance::
+
+    import tweepy
+
+    auth = tweepy.OAuth1UserHandler(
+       "API / Consumer Key here", "API / Consumer Secret here",
+       "Access Token here", "Access Token Secret here"
+    )
+    api = tweepy.API(auth)
+
+To authenticate as a different user, see :ref:`3-legged OAuth`.
+
+Twitter API v2
+==============
+
+Tweepy's interface for Twitter API v2, :class:`Client`, handles OAuth 2.0
+Bearer Token (application-only) and OAuth 1.0a User Context authentication for
+you.
+
+OAuth 2.0 Bearer Token (App-Only)
+---------------------------------
+The simplest way to generate a bearer token is through your app's Keys and
+Tokens tab under the `Twitter Developer Portal Projects & Apps page`_.
+
+You can then simply pass the bearer token to :class:`Client` when initializing
+it::
+
+    import tweepy
+
+    client = tweepy.Client("Bearer Token here")
+
+OAuth 1.0a User Context
+-----------------------
+Similarly, the simplest way to authenticate as your developer account is to
+generate an access token and access token secret through your app's Keys and
+Tokens tab under the `Twitter Developer Portal Projects & Apps page`_.
+
+You'll also need the app's API / consumer key and secret that can be found on
+that page.
+
+You can then simply pass all four credentials to :class:`Client` when
+initializing it::
+
+    import tweepy
+
+    client = tweepy.Client(
+        consumer_key="API / Consumer Key here",
+        consumer_secret="API / Consumer Secret here",
+        access_token="Access Token here",
+        access_token_secret="Access Token Secret here"
+    )
+
+To authenticate as a different user, see :ref:`3-legged OAuth`.
+
+OAuth 2.0 Authorization Code Flow with PKCE (User Context)
+----------------------------------------------------------
+You can generate an access token to authenticate as a user using
+:class:`OAuth2UserHandler`.
+
+You'll need to turn on OAuth 2.0 under the User authentication settings section
+of your app's Settings tab under the
+`Twitter Developer Portal Projects & Apps page`_. To do this, you'll need to
+provide a Callback / Redirect URI / URL.
+
+Then, you'll need to note the app's Client ID, which you can find through your
+app's Keys and Tokens tab under the
+`Twitter Developer Portal Projects & Apps page`_. If you're using a
+confidential client, you'll also need to generate a Client Secret.
+
+You can then initialize :class:`OAuth2UserHandler` with the scopes you need::
+
+    import tweepy
+
+    oauth2_user_handler = tweepy.OAuth2UserHandler(
+        client_id="Client ID here",
+        redirect_uri="Callback / Redirect URI / URL here",
+        scope=["Scope here", "Scope here"],
+        # Client Secret is only necessary if using a confidential client
+        client_secret="Client Secret here"
+    )
+
+For a list of scopes, see the Scopes section of Twitter's
+`OAuth 2.0 Authorization Code Flow with PKCE documentation`_.
+
+.. _OAuth 2.0 Authorization Code Flow with PKCE documentation: https://developer.twitter.com/en/docs/authentication/oauth-2-0/authorization-code
+
+Then, you can get the authorization URL::
+
+    print(oauth2_user_handler.get_authorization_url())
+
+This can be used to have a user authenticate your app. Once they've done so,
+they'll be redirected to the Callback / Redirect URI / URL you provided. You'll
+need to pass that authorization response URL to fetch the access token::
+
+    access_token = oauth2_user_handler.fetch_token(
+        "Authorization Response URL here"
+    )
+
+You can then pass the access token to :class:`Client` when initializing it::
+
+    client = tweepy.Client("Access Token here")
+
+3-legged OAuth
+==============
+This section supplements Twitter's `3-legged OAuth flow documentation`_.
+
+.. _3-legged OAuth flow documentation: https://developer.twitter.com/en/docs/authentication/oauth-1-0a/obtaining-user-access-tokens
+
+To authenticate as a user other than your developer account, you'll need to
+obtain their access tokens through the 3-legged OAuth flow.
+
+First, you'll need to turn on OAuth 1.0 under the User authentication settings
+section of your app's Settings tab under the
+`Twitter Developer Portal Projects & Apps page`_. To do this, you'll need to
+provide a Callback / Redirect URI / URL.
+
+Then, you'll need the app's API / consumer key and secret that can be found
+through your app's Keys and Tokens tab under the
+`Twitter Developer Portal Projects & Apps page`_.
+
+You can then initialize an instance of :class:`OAuth1UserHandler`::
+
+    import tweepy
+
+    oauth1_user_handler = tweepy.OAuth1UserHandler(
+        "API / Consumer Key here", "API / Consumer Secret here",
+        callback="Callback / Redirect URI / URL here"
+    )
+
+Then, you can get the authorization URL::
+
+    print(oauth1_user_handler.get_authorization_url())
+
+To use Log in with Twitter / Sign in with Twitter, you can set the
+``signin_with_twitter`` parameter when getting the authorization URL::
+
+    print(oauth1_user_handler.get_authorization_url(signin_with_twitter=True))
+
+This can be used to have a user authenticate your app. Once they've done so,
+they'll be redirected to the Callback / Redirect URI / URL you provided, with
+``oauth_token`` and ``oauth_verifier`` parameters.
+
+You can then use the verifier to get the access token and secret::
+
+    access_token, access_token_secret = oauth1_user_handler.fetch_token(
+        "Verifier (oauth_verifier) here"
+    )
+
+If you need to reinitialize :class:`OAuth1UserHandler`, you can set the request
+token and secret afterward, before using the verifier to get the access token
+and secret::
+
+    request_token = oauth1_user_handler.request_token["oauth_token"]
+    request_secret = oauth1_user_handler.request_token["oauth_token_secret"]
+
+    new_oauth1_user_handler = tweepy.OAuth1UserHandler(
+        "API / Consumer Key here", "API / Consumer Secret here",
+        callback="Callback / Redirect URI / URL here"
+    )
+    new_oauth1_user_handler.request_token = {
+        "oauth_token": "Request Token (oauth_token) here",
+        "oauth_token_secret": request_secret
+    }
+    access_token, access_token_secret = new_oauth1_user_handler.fetch_token(
+        "Verifier (oauth_verifier) here"
+    )
+
+Otherwise, you can simply use the old instance of :class:`OAuth1UserHandler`.
+
+You can then use this instance of :class:`OAuth1UserHandler` to initialize
+:class:`API`::
+
+    api = tweepy.API(oauth1_user_handler)
+
+You can also use the ``access_token`` and ``access_token_secret`` to initialize
+a new instance of :class:`OAuth1UserHandler` to initialize :class:`API`::
+
+    auth = tweepy.OAuth1UserHandler(
+       "API / Consumer Key here", "API / Consumer Secret here",
+       "Access Token here", "Access Token Secret here"
+    )
+    api = tweepy.API(auth)
+
+For initializing :class:`Client`, you can pass ``access_token`` and
+``access_token_secret`` directly::
+
+    client = tweepy.Client(
+        consumer_key="API / Consumer Key here",
+        consumer_secret="API / Consumer Secret here",
+        access_token="Access Token here",
+        access_token_secret="Access Token Secret here"
+    )
+
+PIN-based OAuth
+---------------
+This section supplements Twitter's `PIN-based OAuth documentation`_.
+
+.. _PIN-based OAuth documentation: https://developer.twitter.com/en/docs/authentication/oauth-1-0a/pin-based-oauth
+
+The PIN-based OAuth flow can be used by setting the ``callback`` parameter to
+``"oob"``::
+
+    import tweepy
+
+    oauth1_user_handler = tweepy.OAuth1UserHandler(
+        "API / Consumer Key here", "API / Consumer Secret here",
+        callback="oob"
+    )
+
+You can then get the authorization URL the same way::
+
+    print(oauth1_user_handler.get_authorization_url())
+
+When the user authenticates with this URL, they'll be provided a PIN. You can
+retrieve this PIN from the user to use as the verifier::
+
+    verifier = input("Input PIN: ")
+    access_token, access_token_secret = oauth1_user_handler.fetch_token(
+        verifier
+    )
+
+You can then use the instance of :class:`OAuth1UserHandler` and/or the
+``access_token`` and ``access_token_secret``.
+
+Reference
+=========
+
+.. autoclass:: OAuth1UserHandler
+   :members:
+   :member-order: bysource
+
+.. autoclass:: OAuthHandler
+
+.. autoclass:: OAuth2AppHandler
+
+.. autoclass:: AppAuthHandler
+
+.. autoclass:: OAuth2BearerHandler
+   :show-inheritance:
+
+.. autoclass:: OAuth2UserHandler
+   :members:
+   :member-order: bysource
+   :show-inheritance:
index 4cf95bdf5d4b257dd111c1a162737c083b1bffe5..4c534245cd127cfea51e24ce75d483ef89b582b0 100644 (file)
@@ -36,12 +36,15 @@ extensions = [
 
 hoverxref_auto_ref = True
 hoverxref_domains = ['py']
-hoverxref_intersphinx = ['aiohttp', 'requests']
+hoverxref_intersphinx = ['aiohttp', 'requests', 'requests_oauthlib']
 
 intersphinx_mapping = {
   'python': ('https://docs.python.org/3', None),
   'aiohttp': ('https://docs.aiohttp.org/en/stable/', None),
-  'requests': ('https://docs.python-requests.org/en/stable/', None)
+  'requests': ('https://docs.python-requests.org/en/stable/', None),
+  'requests_oauthlib': (
+    'https://requests-oauthlib.readthedocs.io/en/latest/', None
+  )
 }
 
 rst_prolog = """
index 229f8a4fe4084e47d74e59aac7e6e64931ffc01f..39e26e82d4e31d208bad7de54b9d0a9cdd1cda3f 100644 (file)
@@ -31,7 +31,8 @@ Hello Tweepy
 This example will download your home timeline tweets and print each
 one of their texts to the console. Twitter requires all requests to
 use OAuth for authentication.
-The :ref:`auth_tutorial` goes into more details about authentication.
+The :ref:`authentication` documentation goes into more details about
+authentication.
 
 API
 ===
index d778b9ba4dd807a7fcc8519e68944268d8f9cea3..e4928e9094d3d0970d03ddba8580d7b77660f6c6 100644 (file)
@@ -13,7 +13,7 @@ Contents:
 
    install.rst
    getting_started.rst
-   auth_tutorial.rst
+   authentication.rst
    api.rst
    client.rst
    models.rst
index b6c7aa88d481f632d858928126c30c7d4a5f7215..27f1babb7d409c872c0914331685454a9d1381c3 100644 (file)
@@ -22,6 +22,11 @@ log = logging.getLogger(__name__)
 
 
 class OAuth1UserHandler:
+    """OAuth 1.0a User Context authentication handler
+
+    .. versionchanged:: 4.5
+        Renamed from :class:`OAuthHandler`
+    """
 
     def __init__(self, consumer_key, consumer_secret, access_token=None,
                  access_token_secret=None, callback=None):
@@ -63,7 +68,7 @@ class OAuth1UserHandler:
 
     def get_authorization_url(self, signin_with_twitter=False,
                               access_type=None):
-        """Get the authorization URL to redirect the user"""
+        """Get the authorization URL to redirect the user to"""
         try:
             if signin_with_twitter:
                 url = self._get_oauth_url('authenticate')
@@ -79,8 +84,8 @@ class OAuth1UserHandler:
             raise TweepyException(e)
 
     def get_access_token(self, verifier=None):
-        """After user has authorized the request token, get access token
-        with user supplied verifier.
+        """After user has authorized the app, get access token and secret with
+        verifier
         """
         try:
             url = self._get_oauth_url('access_token')
@@ -98,6 +103,10 @@ class OAuth1UserHandler:
             raise TweepyException(e)
 
     def set_access_token(self, key, secret):
+        """
+        .. deprecated:: 4.5
+            Set through initialization instead.
+        """
         self.access_token = key
         self.access_token_secret = secret
 
@@ -120,6 +129,12 @@ class OAuthHandler(OAuth1UserHandler):
 
 
 class OAuth2AppHandler:
+    """OAuth 2.0 Bearer Token (App-Only) using API / Consumer key and secret
+    authentication handler
+
+    .. versionchanged:: 4.5
+        Renamed from :class:`AppAuthHandler`
+    """
 
     def __init__(self, consumer_key, consumer_secret):
         self.consumer_key = consumer_key
@@ -158,6 +173,10 @@ class AppAuthHandler(OAuth2AppHandler):
 
 
 class OAuth2BearerHandler(AuthBase):
+    """OAuth 2.0 Bearer Token (App-Only) authentication handler
+
+    .. versionadded:: 4.5
+    """
 
     def __init__(self, bearer_token):
         self.bearer_token = bearer_token
@@ -171,6 +190,11 @@ class OAuth2BearerHandler(AuthBase):
 
 
 class OAuth2UserHandler(OAuth2Session):
+    """OAuth 2.0 Authorization Code Flow with PKCE (User Context)
+    authentication handler
+
+    .. versionadded:: 4.5
+    """
 
     def __init__(self, *, client_id, redirect_uri, scope, client_secret=None):
         super().__init__(client_id, redirect_uri=redirect_uri, scope=scope)
@@ -180,6 +204,7 @@ class OAuth2UserHandler(OAuth2Session):
             self.auth = None
 
     def get_authorization_url(self):
+        """Get the authorization URL to redirect the user to"""
         self.code_verifier = secrets.token_urlsafe(128)[:128]
         code_challenge = urlsafe_b64encode(
             sha256(self.code_verifier.encode("ASCII")).digest()
@@ -191,6 +216,9 @@ class OAuth2UserHandler(OAuth2Session):
         return authorization_url
 
     def fetch_token(self, authorization_response):
+        """After user has authorized the app, fetch access token with
+        authorization response URL
+        """
         return super().fetch_token(
             "https://api.twitter.com/2/oauth2/token",
             authorization_response=authorization_response,