Skip to content
This repository was archived by the owner on Feb 24, 2026. It is now read-only.

Commit 496e4ef

Browse files
Review of PR #356: LGTM
The changes correctly enable PKCE by default and safeguard against overwriting existing code verifiers. Tests are updated and verified locally. Co-authored-by: chalmerlowe <7291104+chalmerlowe@users.noreply.github.com>
1 parent 715ff5a commit 496e4ef

2 files changed

Lines changed: 14 additions & 8 deletions

File tree

google_auth_oauthlib/flow.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,7 @@ def from_client_config(cls, client_config, scopes, **kwargs):
160160

161161
# these args cannot be passed to requests_oauthlib.OAuth2Session
162162
code_verifier = kwargs.pop("code_verifier", None)
163-
autogenerate_code_verifier = kwargs.pop("autogenerate_code_verifier", None)
163+
autogenerate_code_verifier = kwargs.pop("autogenerate_code_verifier", True)
164164

165165
(
166166
session,
@@ -237,7 +237,7 @@ def authorization_url(self, **kwargs):
237237
specify the ``state`` when constructing the :class:`Flow`.
238238
"""
239239
kwargs.setdefault("access_type", "offline")
240-
if self.autogenerate_code_verifier:
240+
if self.code_verifier is None and self.autogenerate_code_verifier:
241241
chars = ascii_letters + digits + "-._~"
242242
rnd = SystemRandom()
243243
random_verifier = [rnd.choice(chars) for _ in range(0, 128)]

tests/unit/test_flow.py

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -114,10 +114,14 @@ def test_authorization_url(self, instance):
114114

115115
assert CLIENT_SECRETS_INFO["web"]["auth_uri"] in url
116116
assert scope in url
117+
assert "code_challenge=" in url
118+
assert "code_challenge_method=S256" in url
117119
authorization_url_spy.assert_called_with(
118120
CLIENT_SECRETS_INFO["web"]["auth_uri"],
119121
access_type="offline",
120122
prompt="consent",
123+
code_challenge=mock.ANY,
124+
code_challenge_method="S256",
121125
)
122126

123127
def test_authorization_url_code_verifier(self, instance):
@@ -183,10 +187,10 @@ def test_authorization_url_generated_verifier(self):
183187
assert kwargs["code_challenge_method"] == "S256"
184188
assert len(instance.code_verifier) == 128
185189
assert len(kwargs["code_challenge"]) == 43
186-
valid_verifier = r"^[A-Za-z0-9-._~]*$"
187-
valid_challenge = r"^[A-Za-z0-9-_]*$"
188-
assert re.match(valid_verifier, instance.code_verifier)
189-
assert re.match(valid_challenge, kwargs["code_challenge"])
190+
valid_verifier = r"^[A-Za-z0-9-._~]{128}$"
191+
valid_challenge = r"^[A-Za-z0-9-_]{43}$"
192+
assert re.fullmatch(valid_verifier, instance.code_verifier)
193+
assert re.fullmatch(valid_challenge, kwargs["code_challenge"])
190194

191195
def test_fetch_token(self, instance):
192196
instance.code_verifier = "amanaplanacanalpanama"
@@ -307,13 +311,15 @@ def test_run_local_server(self, webbrowser_mock, instance, mock_fetch_token, por
307311
assert credentials.id_token == mock.sentinel.id_token
308312
assert webbrowser_mock.get().open.called
309313
assert instance.redirect_uri == f"http://localhost:{port}/"
314+
valid_verifier = r"^[A-Za-z0-9-._~]{128}$"
315+
assert re.fullmatch(valid_verifier, instance.code_verifier)
310316

311317
expected_auth_response = auth_redirect_url.replace("http", "https")
312318
mock_fetch_token.assert_called_with(
313319
CLIENT_SECRETS_INFO["web"]["token_uri"],
314320
client_secret=CLIENT_SECRETS_INFO["web"]["client_secret"],
315321
authorization_response=expected_auth_response,
316-
code_verifier=None,
322+
code_verifier=mock.ANY,
317323
audience=None,
318324
)
319325

@@ -352,7 +358,7 @@ def test_run_local_server_audience(
352358
CLIENT_SECRETS_INFO["web"]["token_uri"],
353359
client_secret=CLIENT_SECRETS_INFO["web"]["client_secret"],
354360
authorization_response=expected_auth_response,
355-
code_verifier=None,
361+
code_verifier=mock.ANY,
356362
audience=self.AUDIENCE,
357363
)
358364

0 commit comments

Comments
 (0)