1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285
|
.. _oauth:
Authenticating via OAuth
========================
PRAW supports all three types of applications that can be registered on Reddit. Those
are:
- `Web Applications
<https://github.com/reddit-archive/reddit/wiki/OAuth2-App-Types#web-app>`_
- `Installed Applications
<https://github.com/reddit-archive/reddit/wiki/OAuth2-App-Types#installed-app>`_
- `Script Applications
<https://github.com/reddit-archive/reddit/wiki/OAuth2-App-Types#script-app>`_
Before you can use any one of these with PRAW, you must first `register
<https://old.reddit.com/prefs/apps/>`_ an application of the appropriate type on Reddit.
If your application does not require a user context, it is :ref:`read-only
<read_only_application>`.
PRAW supports the flows that each of these applications can use. The following table
defines which application types can use which flows:
.. include:: authentication_flow_table.txt
.. warning::
For the sake of brevity, the following examples pass authentication information via
arguments to :class:`.Reddit`. If you do this, you need to be careful not to reveal
this information to the outside world if you share your code. It is recommended to
use a :ref:`praw.ini file <praw.ini>` in order to keep your authentication
information separate from your code.
.. _password_flow:
Password Flow
-------------
**Password Flow** is the simplest type of authentication flow to work with because no
callback process is involved in obtaining an ``access_token``.
While **password flow** applications do not involve a redirect URI, Reddit still
requires that you provide one when registering your script application --
``http://localhost:8080`` is a simple one to use.
In order to use a **password flow** application with PRAW you need four pieces of
information:
:client_id: The client ID is at least a 14-character string listed just under "personal
use script" for the desired `developed application
<https://www.reddit.com/prefs/apps/>`_
:client_secret: The client secret is at least a 27-character string listed adjacent to
``secret`` for the application.
:password: The password for the Reddit account used to register the application.
:username: The username of the Reddit account used to register the application.
With this information authorizing as ``username`` using a **password flow** app is as
simple as:
.. code-block:: python
reddit = praw.Reddit(
client_id="SI8pN3DSbt0zor",
client_secret="xaxkj7HNh8kwg8e5t4m6KvSrbTI",
password="1guiwevlfo00esyy",
user_agent="testscript by u/fakebot3",
username="fakebot3",
)
To verify that you are authenticated as the correct user run:
.. code-block:: python
print(reddit.user.me())
The output should contain the same name as you entered for ``username``.
.. note::
If the following exception is raised, double-check your credentials, and ensure that
that the username and password you are using are for the same user with which the
application is associated:
.. code-block::
OAuthException: invalid_grant error processing request
.. _2fa:
Two-Factor Authentication
~~~~~~~~~~~~~~~~~~~~~~~~~
A 2FA token can be used by joining it to the password with a colon:
.. code-block:: python
reddit = praw.Reddit(
client_id="SI8pN3DSbt0zor",
client_secret="xaxkj7HNh8kwg8e5t4m6KvSrbTI",
password="1guiwevlfo00esyy:955413",
user_agent="testscript by u/fakebot3",
username="fakebot3",
)
However, for such an app there is little benefit to using 2FA. The token must be
refreshed after one hour; therefore, the 2FA secret would have to be stored along with
the rest of the credentials in order to generate the token, which defeats the point of
having an extra credential beyond the password.
If you do choose to use 2FA, you must handle the ``prawcore.OAuthException`` that will
be raised by API calls after one hour.
.. _code_flow:
Code Flow
---------
A **code flow** application is useful for two primary purposes:
- You have an application and want to be able to access Reddit from your users'
accounts.
- You have a personal-use script application and you either want to
- limit the access one of your PRAW-based programs has to Reddit
- avoid the hassle of 2FA (described above)
- not pass your username and password to PRAW (and thus not keep it in memory)
When registering your application you must provide a valid redirect URI. If you are
running a website you will want to enter the appropriate callback URL and configure that
endpoint to complete the code flow.
If you aren't actually running a website, you can follow the :ref:`refresh_token`
tutorial to learn how to obtain and use the initial refresh token.
Whether or not you follow the :ref:`refresh_token` tutorial there are two processes
involved in obtaining access or refresh tokens.
.. _auth_url:
Obtain the Authorization URL
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The first step to completing the **code flow** is to obtain the authorization URL. You
can do that as follows:
.. code-block:: python
reddit = praw.Reddit(
client_id="SI8pN3DSbt0zor",
client_secret="xaxkj7HNh8kwg8e5t4m6KvSrbTI",
redirect_uri="http://localhost:8080",
user_agent="testscript by u/fakebot3",
)
print(reddit.auth.url(scopes=["identity"], state="...", duration="permanent"))
The above will output an authorization URL for a permanent token (i.e., the resulting
authorization will include both a short-lived ``access_token``, and a longer-lived,
single use ``refresh_token``) that has only the ``identity`` scope. See :meth:`.url` for
more information on these parameters.
This URL should be accessed by the account that desires to authorize their Reddit access
to your application. On completion of that flow, the user's browser will be redirected
to the specified ``redirect_uri``. After verifying the ``state`` and extracting the
``code`` you can obtain the refresh token via:
.. code-block:: python
print(reddit.auth.authorize(code))
print(reddit.user.me())
The first line of output is the ``refresh_token``. You can save this for later use (see
:ref:`using_refresh_tokens`).
The second line of output reveals the name of the :class:`.Redditor` that completed the
code flow. It also indicates that the :class:`.Reddit` instance is now associated with
that account.
The code flow can be used with an **installed** application just as described above with
one change: set the value of ``client_secret`` to ``None`` when initializing
:class:`.Reddit`.
.. _implicit_flow:
Implicit Flow
-------------
The **implicit flow** requires a similar instantiation of the :class:`.Reddit` class as
done in :ref:`code_flow`, however, the token is returned directly as part of the
redirect. For the implicit flow call :meth:`.url` like so:
.. code-block:: python
print(reddit.auth.url(scopes=["identity"], state="...", implicit=True))
Then use :meth:`.implicit` to provide the authorization to the :class:`.Reddit`
instance.
.. _read_only_application:
Read-Only Mode
--------------
All application types support a read-only mode. Read-only mode provides access to Reddit
like a logged out user would see including the default subreddits in the
``reddit.front`` listings.
In the absence of a ``refresh_token`` both :ref:`code_flow` and :ref:`implicit_flow`
applications start in the **read-only** mode. With such applications **read-only** mode
is disabled when :meth:`.authorize`, or :meth:`.implicit` are successfully called.
:ref:`password_flow` applications start up with **read-only** mode disabled.
Read-only mode can be toggled via:
.. code-block:: python
# Enable read-only mode
reddit.read_only = True
# Disable read-only mode (must have a valid authorization)
reddit.read_only = False
Application-Only Flows
~~~~~~~~~~~~~~~~~~~~~~
The following flows are the **read-only mode** flows for Reddit applications
.. _application_only_client_credentials_flow:
Application-Only (Client Credentials)
+++++++++++++++++++++++++++++++++++++
This is the default flow for **read-only mode** in script and web applications. The idea
behind this is that Reddit *can* trust these applications as coming from a given
developer, however the application requires no logged-in user context.
An installed application *cannot* use this flow, because Reddit requires a
``client_secret`` to be given if this flow is being used. In other words, installed
applications are not considered confidential clients.
.. _application_only_installed_client_flow:
Application-Only (Installed Client)
+++++++++++++++++++++++++++++++++++
This is the default flow for **read-only mode** in installed applications. The idea
behind this is that Reddit *might not be able* to trust these applications as coming
from a given developer. This would be able to happen if someone other than the developer
can potentially replicate the client information and then pretend to be the application,
such as in installed applications where the end user could retrieve the ``client_id``.
.. note::
No benefit is really gained from this in script or web apps. The one exception is
for when a script or web app has multiple end users, this will allow you to give
Reddit the information needed in order to distinguish different users of your app
from each other (as the supplied device ID *should* be a unique string per both
device (in the case of a web app, server) and user (in the case of a web app,
browser session).
.. _using_refresh_tokens:
Using a Saved Refresh Token
---------------------------
A saved refresh token can be used to immediately obtain an authorized instance of
:class:`.Reddit` like so:
.. code-block:: python
reddit = praw.Reddit(
client_id="SI8pN3DSbt0zor",
client_secret="xaxkj7HNh8kwg8e5t4m6KvSrbTI",
refresh_token="WeheY7PwgeCZj4S3QgUcLhKE5S2s4eAYdxM",
user_agent="testscript by u/fakebot3",
)
print(reddit.auth.scopes())
The output from the above code displays which scopes are available on the
:class:`.Reddit` instance.
.. note::
Observe that ``redirect_uri`` does not need to be provided in such cases. It is only
needed when :meth:`.url` is used.
|