Python – HttpAccessTokenRefreshError : invalid_grant . .. One hour limit to refresh tokens

HttpAccessTokenRefreshError : invalid_grant . .. One hour limit to refresh tokens… here is a solution to the problem.

HttpAccessTokenRefreshError : invalid_grant . .. One hour limit to refresh tokens

I’ve looked at other issues on this topic and it doesn’t seem to match my error. Error running Google Sheets APIv4:

Raises HttpAccessTokenRefreshError(error_msg, status=resp.status)
HttpAccessTokenRefreshError:invalid_grant

An error occurred on the service.spreadsheets().values().get(spreadsheetId=key, range=ranges).execute() line

This error only pops up occasionally. If I do nothing, just run the code again. It will take me through the identity verification process again and then I get

Validation succeeded.
Store credentials to C:\Users\jason\.credentials\sheets.googleapis.com-python-quickstart.json

After that, I can run any code for a while until the same HttpAccessTokenRefreshError: invalid_grant pops up again and I have to revalidate again.

How can this be prevented?

I’m using code from developers.google.com/sheets/api/quickstart/python.

I tried using ntp to synchronize time

import time
import os
try:
    import ntplib
    client = ntplib. NTPClient()
    response = client.request('pool.ntp.org')
    os.system('date ' + time.strftime('%m%d%H%M%Y.%S',time.localtime(response.tx_time)))
except:
    print('Could not sync with time server.')

print('Done.')

But get:

The system cannot accept the date entered.
Enter the new data: (mm-dd-yy)

After I enter the current date, nothing happens.

I’ve seen this page too. https://blog.timekit.io/google-oauth-invalid-grant-nightmare-and-how-to-fix-it-9f4efaf1da35#.5utz2vcn6

This issue also occurs when I run code that takes more than 1 hour to complete. On the refresh token. It’s always a bomb.

Now I’m thinking that the token granted only lasts for an hour, and when refreshed, it always bombs.

I’ve posted the connection code:

class APIv4:
    def __init__(self):
    credentials = get_credentials()
    http = credentials.authorize(httplib2. Http())
    discoveryUrl = ('https://sheets.googleapis.com/$discovery/rest?'
                    'version=v4')
    self.service = discovery.build('sheets', 'v4', http=http,
                              discoveryServiceUrl=discoveryUrl)

def get_credentials():
    """Gets valid user credentials from storage.

If nothing has been stored, or if the stored credentials are invalid,
    the OAuth2 flow is completed to obtain the new credentials.

Returns:
        Credentials, the obtained credential.
    """
    home_dir = os.path.expanduser('~')
    credential_dir = os.path.join(home_dir, '.credentials')
    if not os.path.exists(credential_dir):
        os.makedirs(credential_dir)
    credential_path = os.path.join(credential_dir,
                                   'sheets.googleapis.com-python-quickstart.json')

store = Storage(credential_path)
    credentials = store.get()
    if not credentials or credentials.invalid:
        flow = client.flow_from_clientsecrets(CLIENT_SECRET_FILE, SCOPES)
        flow.user_agent = APPLICATION_NAME
        if flags:
            credentials = tools.run_flow(flow, store, flags)
        else: # Needed only for compatibility with Python 2.6
            credentials = tools.run(flow, store)
        print('Storing credentials to ' + credential_path)
    return credentials

Solution

In general, there seems to be a problem with the refresh of accessing tokens between calls.

This either means that some of your credentials are not passed correctly, or there is a problem with your local computer time (although it seems less likely than the first option).

I propose to investigate the possibilities described in this issue: https://github.com/google/oauth2client/issues/451 :

  1. (Unlikely) why you wouldn’t try to force a clock update using ntpdate. Install NTP and give it a try because one user said it worked for him
  2. Ok. After a loong research I guess I found out the problem. In fact, refresh_token was missing from the user credential, but the issue was tricky.

    The refresh token is given for the FIRST time when the application asks the user for permissions. The refresh token is given ONLY IF the flow’s step 1 includes the parameters approval_prompt=”force”

    For some reason the user (me) hadn’t got refresh_token in user’s credentials, so I revoked permissions from the application on My Account -> Security -> Applications, and restarted the OAuth dance again. Now I got refresh_token.

#2 Update to option:

Follow this guide and the above suggestion, I believe you must add to this snippet ( Taken directly from the guide):

# Create a state token to prevent request forgery.
# Store it in the session for later validation.
state = hashlib.sha256(os.urandom(1024)).hexdigest()
session['state'] = state
# Set the client ID, token state, and application name in the HTML while
# serving it.
response = make_response(
    render_template('index.html',
                    CLIENT_ID=CLIENT_ID,
                    STATE=state,
                    APPLICATION_NAME=APPLICATION_NAME))

prompt=consent line, and then proceed to the third step of the response referenced above (option 2).

Another option is to use approval_prompt=force, but you have to choose between the two because they don’t work well together.

Good luck 🙂

Related Problems and Solutions