Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refresh_token not regenerated with current authorization_url defaults. #348

Closed
octaflop opened this issue May 6, 2024 · 4 comments · May be fixed by #349
Closed

Refresh_token not regenerated with current authorization_url defaults. #348

octaflop opened this issue May 6, 2024 · 4 comments · May be fixed by #349
Assignees

Comments

@octaflop
Copy link

octaflop commented May 6, 2024

Thanks for stopping by to let us know something could be better!

PLEASE READ: If you have a support contract with Google, please create an issue in the support console instead of filing on GitHub. This will ensure a timely response.

Please run down the following list and make sure you've tried the usual "quick fixes":

If you are still having issues, please be sure to include as much information as possible:

Environment details

  • OS type and version:
  • Python version: python --version
  • pip version: pip --version
  • google-auth-oauthlib version: pip show google-auth-oauthlib

Steps to reproduce

  1. Auth and save a token.json
  2. Delete the token.json
  3. Try to use the token.json or note it doesn't have a refresh_token.
  4. The token.json will fail to work

Code example

def create_service() -> discovery:
    token_path = Path(__file__).parent / 'token.json'
    credentials_path = Path(__file__).parent / 'client_secrets.json'
    creds = None
    if token_path.exists():
        try:
            creds = Credentials.from_authorized_user_file(str(token_path), SCOPES)
        except ValueError:
            creds = None
    # If there are no (valid) credentials available, let the user log in.
    if not creds or not creds.valid:
        if creds and creds.expired and creds.refresh_token:
            creds.refresh(Request())
        else:
            flow = InstalledAppFlow.from_client_secrets_file(
                str(credentials_path), SCOPES)
            try:
                creds = flow.run_local_server(port=8080, open_browser=False)

            except MismatchingStateError:
                print("State mismatch error during OAuth process. Trying again...")
                creds = flow.run_local_server(port=8080, open_browser=False)

        # Save the credentials for the next run
        with open(token_path, 'w') as token:
            token.write(creds.to_json())

    service = build('drive', 'v3', credentials=creds)
    return service

Stack trace

NA -- ValueError

Making sure to follow these steps will guarantee the quickest resolution possible.

Thanks!

Proposed fix (PR incoming)

add prompt=consent to the authorization_url as a default. As a current workaround I am finding this to work:

url_args = {
    'access_type': 'offline',
    'prompt': 'consent'
}
flow = InstalledAppFlow.from_client_secrets_file(
    str(credentials_path), SCOPES)
try:
    creds = flow.run_local_server(port=8080, open_browser=False, **url_args)

except MismatchingStateError:
    print("State mismatch error during OAuth process. Trying again...")
    creds = flow.run_local_server(port=8080, open_browser=False, **url_args)
@arithmetic1728
Copy link
Contributor

I am inclined not to add prompt=consent because this changes the behavior of flow.run_local_server, it will make flow.run_local_server always show the consent page. https://developers.google.com/identity/openid-connect/openid-connect#authenticationuriparameters

@octaflop
Copy link
Author

Great point. I'm not sure how best to approach parameterizing or retrying in this edge case. Any thoughts would be helpful.

@arithmetic1728
Copy link
Contributor

if not creds or not creds.valid:
    if creds and creds.expired and creds.refresh_token:
        try:
            creds.refresh(Request())
            # Save the credentials for the next run
            with open(token_path, 'w') as token:
                token.write(creds.to_json())
        except google.auth.exceptions.RefreshError:
            # fall back to run_local_server
            pass

    flow = InstalledAppFlow.from_client_secrets_file(
            str(credentials_path), SCOPES)
    url_args = {
        'access_type': 'offline',
        'prompt': 'consent'
    }
    try:
        creds = flow.run_local_server(port=8080, open_browser=False, **url_args)
    except MismatchingStateError:
        print("State mismatch error during OAuth process. Trying again...")
        creds = flow.run_local_server(port=8080, open_browser=False, **url_args)

    # Save the credentials for the next run
    with open(token_path, 'w') as token:
        token.write(creds.to_json())

you may try this approach. If there is refresh token, just refresh an access token; if we cannot refresh or refresh fails due to expired refresh token, fall back to run_local_server with the url_args, this way you will get a new refresh_token.

@arithmetic1728 arithmetic1728 self-assigned this May 17, 2024
@arithmetic1728
Copy link
Contributor

Please reopen the issue if you have any questions. Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants