@@ -95,7 +95,8 @@ class Flow(object):
9595
9696 def __init__ (
9797 self , oauth2session , client_type , client_config ,
98- redirect_uri = None , code_verifier = None ):
98+ redirect_uri = None , code_verifier = None ,
99+ autogenerate_code_verifier = False ):
99100 """
100101 Args:
101102 oauth2session (requests_oauthlib.OAuth2Session):
@@ -108,8 +109,9 @@ def __init__(
108109 creation time. Otherwise, it will need to be set using
109110 :attr:`redirect_uri`.
110111 code_verifier (str): random string of 43-128 chars used to verify
111- the key exchange.using PKCE. Auto-generated if not provided.
112-
112+ the key exchange.using PKCE.
113+ autogenerate_code_verifier (bool): If true, auto-generate a
114+ code_verifier.
113115 .. _client secrets:
114116 https://developers.google.com/api-client-library/python/guide
115117 /aaa_client_secrets
@@ -122,6 +124,7 @@ def __init__(
122124 """requests_oauthlib.OAuth2Session: The OAuth 2.0 session."""
123125 self .redirect_uri = redirect_uri
124126 self .code_verifier = code_verifier
127+ self .autogenerate_code_verifier = autogenerate_code_verifier
125128
126129 @classmethod
127130 def from_client_config (cls , client_config , scopes , ** kwargs ):
@@ -155,12 +158,25 @@ def from_client_config(cls, client_config, scopes, **kwargs):
155158 raise ValueError (
156159 'Client secrets must be for a web or installed app.' )
157160
161+ # these args cannot be passed to requests_oauthlib.OAuth2Session
162+ code_verifier = kwargs .pop ('code_verifier' , None )
163+ autogenerate_code_verifier = kwargs .pop (
164+ 'autogenerate_code_verifier' , None )
165+
158166 session , client_config = (
159167 google_auth_oauthlib .helpers .session_from_client_config (
160168 client_config , scopes , ** kwargs ))
161169
162170 redirect_uri = kwargs .get ('redirect_uri' , None )
163- return cls (session , client_type , client_config , redirect_uri )
171+
172+ return cls (
173+ session ,
174+ client_type ,
175+ client_config ,
176+ redirect_uri ,
177+ code_verifier ,
178+ autogenerate_code_verifier
179+ )
164180
165181 @classmethod
166182 def from_client_secrets_file (cls , client_secrets_file , scopes , ** kwargs ):
@@ -217,18 +233,20 @@ def authorization_url(self, **kwargs):
217233 specify the ``state`` when constructing the :class:`Flow`.
218234 """
219235 kwargs .setdefault ('access_type' , 'offline' )
220- if not self .code_verifier :
236+ if self .autogenerate_code_verifier :
221237 chars = ascii_letters + digits + '-._~'
222238 rnd = SystemRandom ()
223239 random_verifier = [rnd .choice (chars ) for _ in range (0 , 128 )]
224240 self .code_verifier = '' .join (random_verifier )
225- code_hash = hashlib .sha256 ()
226- code_hash .update (str .encode (self .code_verifier ))
227- unencoded_challenge = code_hash .digest ()
228- b64_challenge = urlsafe_b64encode (unencoded_challenge )
229- code_challenge = b64_challenge .decode ().split ('=' )[0 ]
230- kwargs .setdefault ('code_challenge' , code_challenge )
231- kwargs .setdefault ('code_challenge_method' , 'S256' )
241+
242+ if self .code_verifier :
243+ code_hash = hashlib .sha256 ()
244+ code_hash .update (str .encode (self .code_verifier ))
245+ unencoded_challenge = code_hash .digest ()
246+ b64_challenge = urlsafe_b64encode (unencoded_challenge )
247+ code_challenge = b64_challenge .decode ().split ('=' )[0 ]
248+ kwargs .setdefault ('code_challenge' , code_challenge )
249+ kwargs .setdefault ('code_challenge_method' , 'S256' )
232250 url , state = self .oauth2session .authorization_url (
233251 self .client_config ['auth_uri' ], ** kwargs )
234252
0 commit comments