OAuth throws "missing code validator" in Google OAuth2
This seems to be a bug in the 0.4.0 version of google-auth-oauthlib
(see this upstream issue; note that it has been reported after this SO question was posted).
You have the following options:
- As a workaround, you can downgrade the used version:
pip install --upgrade google-auth-oauthlib==0.3.0
- Pass a custom code verifier when instantiating
google_auth_oauthlib.flow.Flow()
, which should be a random string of 43-128 characters used to verify the key exchange using PKCE:
Note: The code is for youroauth2_session, client_config = google_auth_oauthlib.helpers.session_from_client_secrets_file( 'client_secret.json', scopes=['https://www.googleapis.com/auth/drive.file']), ) flow = google_auth_oauthlib.flow.Flow( oauth2_session, client_type='web', client_config=client_config, redirect_uri='https://localhost:5000/oauth2callback/', code_verifier='<random string>' )
login()
function. You will have to slightly adjust it to work in youroauth2callback()
function. - Wait until the bug is fixed in upstream (provided that it is a bug). After that, the code verifier will be auto-generated when not provided.
Based on s3rvac's answer, I dug a bit into the source code and found that the code_verifier
property is in fact auto generated in the authorization_url()
method! So no need to generate one yourself.
In your login()
method, after the call to flow.authorization_url()
, store flow.code_verifier
in the session:
authorization_url, state = flow.authorization_url(
access_type='offline',
include_granted_scopes='true') # code_verifier is set in this method
session['code_verifier'] = flow.code_verifier # Get and store the code
session['state'] = state
return redirect(authorization_url)
Then, in the callback method, just load it back:
flow = google_auth_oauthlib.flow.Flow(
oauth2_session,
client_type='web',
client_config=client_config,
redirect_uri='https://localhost:5000/oauth2callback/',
code_verifier=session.get('code_verifier') # Load the code
)
I use Flow.from_client_config()
to construct a Flow
but I just add this line and it works fine:
flow.code_verifier = session.get('code_verifier')