Skip to content

Commit 1fb16be

Browse files
authored
feat: deprecate OAuth out-of-band flow (#175)
https://developers.googleblog.com/2022/02/making-oauth-flows-safer.html?m=1#disallowed-oob The OAuth out-of-band flow is being deprecated and will stop working completely in October 2022.
1 parent f2fb52e commit 1fb16be

File tree

2 files changed

+70
-26
lines changed

2 files changed

+70
-26
lines changed

google_auth_oauthlib/flow.py

Lines changed: 53 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -15,46 +15,44 @@
1515
"""OAuth 2.0 Authorization Flow
1616
1717
This module provides integration with `requests-oauthlib`_ for running the
18-
`OAuth 2.0 Authorization Flow`_ and acquiring user credentials.
18+
`OAuth 2.0 Authorization Flow`_ and acquiring user credentials. See
19+
`Using OAuth 2.0 to Access Google APIs`_ for an overview of OAuth 2.0
20+
authorization scenarios Google APIs support.
1921
20-
Here's an example of using :class:`Flow` with the installed application
21-
authorization flow::
22+
Here's an example of using :class:`InstalledAppFlow`::
2223
23-
from google_auth_oauthlib.flow import Flow
24+
from google_auth_oauthlib.flow import InstalledAppFlow
2425
2526
# Create the flow using the client secrets file from the Google API
2627
# Console.
27-
flow = Flow.from_client_secrets_file(
28-
'path/to/client_secrets.json',
29-
scopes=['profile', 'email'],
30-
redirect_uri='urn:ietf:wg:oauth:2.0:oob')
28+
flow = InstalledAppFlow.from_client_secrets_file(
29+
'client_secrets.json',
30+
scopes=['profile', 'email'])
3131
32-
# Tell the user to go to the authorization URL.
33-
auth_url, _ = flow.authorization_url(prompt='consent')
34-
35-
print('Please go to this URL: {}'.format(auth_url))
36-
37-
# The user will get an authorization code. This code is used to get the
38-
# access token.
39-
code = input('Enter the authorization code: ')
40-
flow.fetch_token(code=code)
32+
flow.run_local_server()
4133
4234
# You can use flow.credentials, or you can just get a requests session
4335
# using flow.authorized_session.
4436
session = flow.authorized_session()
45-
print(session.get('https://www.googleapis.com/userinfo/v2/me').json())
4637
47-
This particular flow can be handled entirely by using
48-
:class:`InstalledAppFlow`.
38+
profile_info = session.get(
39+
'https://www.googleapis.com/userinfo/v2/me').json()
40+
41+
print(profile_info)
42+
# {'name': '...', 'email': '...', ...}
4943
5044
.. _requests-oauthlib: http://requests-oauthlib.readthedocs.io/en/stable/
5145
.. _OAuth 2.0 Authorization Flow:
5246
https://tools.ietf.org/html/rfc6749#section-1.2
47+
.. _Using OAuth 2.0 to Access Google APIs:
48+
https://developers.google.com/identity/protocols/oauth2
49+
5350
"""
5451
from base64 import urlsafe_b64encode
5552
import hashlib
5653
import json
5754
import logging
55+
import warnings
5856

5957
try:
6058
from secrets import SystemRandom
@@ -72,6 +70,11 @@
7270

7371

7472
_LOGGER = logging.getLogger(__name__)
73+
_OOB_REDIRECT_URIS = [
74+
"urn:ietf:wg:oauth:2.0:oob",
75+
"urn:ietf:wg:oauth:2.0:oob:auto",
76+
"oob",
77+
]
7578

7679

7780
class Flow(object):
@@ -211,6 +214,17 @@ def redirect_uri(self):
211214

212215
@redirect_uri.setter
213216
def redirect_uri(self, value):
217+
if value in _OOB_REDIRECT_URIS:
218+
warnings.warn(
219+
"'{}' is an OOB redirect URI. The OAuth out-of-band (OOB) flow is deprecated. "
220+
"New clients will be unable to use this flow starting on Feb 28, 2022. "
221+
"This flow will be deprecated for all clients on Oct 3, 2022. "
222+
"Migrate to an alternative flow. "
223+
"See https://developers.googleblog.com/2022/02/making-oauth-flows-safer.html?m=1#disallowed-oob".format(
224+
value
225+
),
226+
DeprecationWarning,
227+
)
214228
self.oauth2session.redirect_uri = value
215229

216230
def authorization_url(self, **kwargs):
@@ -325,9 +339,7 @@ class InstalledAppFlow(Flow):
325339
local development or applications that are installed on a desktop operating
326340
system.
327341
328-
This flow has two strategies: The console strategy provided by
329-
:meth:`run_console` and the local server strategy provided by
330-
:meth:`run_local_server`.
342+
This flow uses a local server strategy provided by :meth:`run_local_server`.
331343
332344
Example::
333345
@@ -348,8 +360,8 @@ class InstalledAppFlow(Flow):
348360
# {'name': '...', 'email': '...', ...}
349361
350362
351-
Note that these aren't the only two ways to accomplish the installed
352-
application flow, they are just the most common ways. You can use the
363+
Note that this isn't the only way to accomplish the installed
364+
application flow, just one of the most common. You can use the
353365
:class:`Flow` class to perform the same flow with different methods of
354366
presenting the authorization URL to the user or obtaining the authorization
355367
response, such as using an embedded web view.
@@ -381,6 +393,15 @@ def run_console(
381393
):
382394
"""Run the flow using the console strategy.
383395
396+
.. deprecated:: 0.5.0
397+
Use :meth:`run_local_server` instead.
398+
399+
The OAuth out-of-band (OOB) flow is deprecated. New clients will be unable to
400+
use this flow starting on Feb 28, 2022. This flow will be deprecated
401+
for all clients on Oct 3, 2022. Migrate to an alternative flow.
402+
403+
See https://developers.googleblog.com/2022/02/making-oauth-flows-safer.html?m=1#disallowed-oob"
404+
384405
The console strategy instructs the user to open the authorization URL
385406
in their browser. Once the authorization is complete the authorization
386407
server will give the user a code. The user then must copy & paste this
@@ -399,6 +420,13 @@ def run_console(
399420
for the user.
400421
"""
401422
kwargs.setdefault("prompt", "consent")
423+
warnings.warn(
424+
"New clients will be unable to use `InstalledAppFlow.run_console` "
425+
"starting on Feb 28, 2022. All clients will be unable to use this method starting on Oct 3, 2022. "
426+
"Use `InstalledAppFlow.run_local_server` instead. For details on the OOB flow deprecation, "
427+
"see https://developers.googleblog.com/2022/02/making-oauth-flows-safer.html?m=1#disallowed-oob",
428+
DeprecationWarning,
429+
)
402430

403431
self.redirect_uri = self._OOB_REDIRECT_URI
404432

tests/unit/test_flow.py

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,20 @@ def test_from_client_secrets_file_with_redirect_uri(self):
5858
== mock.sentinel.redirect_uri
5959
)
6060

61+
def test_from_client_secrets_file_with_oob_redirect_uri(self):
62+
with pytest.deprecated_call():
63+
instance = flow.Flow.from_client_secrets_file(
64+
CLIENT_SECRETS_FILE,
65+
scopes=mock.sentinel.scopes,
66+
redirect_uri="urn:ietf:wg:oauth:2.0:oob",
67+
)
68+
69+
assert (
70+
instance.redirect_uri
71+
== instance.oauth2session.redirect_uri
72+
== "urn:ietf:wg:oauth:2.0:oob"
73+
)
74+
6175
def test_from_client_config_installed(self):
6276
client_config = {"installed": CLIENT_SECRETS_INFO["web"]}
6377
instance = flow.Flow.from_client_config(
@@ -286,7 +300,9 @@ def set_token(*args, **kwargs):
286300
def test_run_console(self, input_mock, instance, mock_fetch_token):
287301
input_mock.return_value = mock.sentinel.code
288302
instance.code_verifier = "amanaplanacanalpanama"
289-
credentials = instance.run_console()
303+
304+
with pytest.deprecated_call():
305+
credentials = instance.run_console()
290306

291307
assert credentials.token == mock.sentinel.access_token
292308
assert credentials._refresh_token == mock.sentinel.refresh_token

0 commit comments

Comments
 (0)