HttpAccessTokenRefreshError: invalid_grant ... one hour limit refresh token

HttpAccessTokenRefreshError: invalid_grant ... one hour limit refresh token

我查看了有关此主题的其他问题,它似乎与我的错误不符。当 运行ning Google Sheets APIv4:

时出现错误

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

service.spreadsheets().values().get(spreadsheetId=key, range=ranges).execute()

出现错误

这个错误只是偶尔出现。如果我什么都不做,只是再次 运行 代码。它会带我再次通过身份验证流程,我得到

Authentication successful. Storing credentials to C:\Users\jason\.credentials\sheets.googleapis.com-python-quickstart.json

之后,我可以 运行 任何代码一段时间,直到相同的 HttpAccessTokenRefreshError: invalid_grant 再次弹出,我必须再次重新验证。

如何防止这种情况发生?

我正在使用 developers.google.com/sheets/api/quickstart/python.

找到的代码

我尝试使用ntp与以下

同步时间
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.')

但得到:

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

输入当前日期后,没有任何反应。

我也看过这个页面。 https://blog.timekit.io/google-oauth-invalid-grant-nightmare-and-how-to-fix-it-9f4efaf1da35#.5utz2vcn6

当我 运行 完成超过 1 小时的代码时,也会出现此问题。在刷新令牌上。它总是炸弹。

现在我在想,授予的令牌只持续一个小时,刷新时,它总是炸弹。

我已经发布了连接代码:

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

一般来说,两次调用之间访问令牌的刷新似乎有问题。

这要么意味着您的某些凭据未正确传递,要么您的本地计算机的时间存在问题(尽管似乎比第一个选项可能性小)

我建议研究一下本期的可能性:https://github.com/google/oauth2client/issues/451:

  1. (不太可能)你为什么不尝试用 ntpdate 强制更新时钟呢?安装 ntp 并试一试,因为一位用户说这对他有用
  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 选项更新:

根据此 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 行,然后执行上面引用的响应的第三步(选项 2)。

另一种选择是使用 approval_prompt=force,但您必须在两者之间做出选择,因为它们不能很好地协同工作。

祝你好运:)

一些想法....

您发布的 timekit.io 博客 link 在 运行 替代方案中相当不错。在你的情况下,这听起来不像是时间相关的,而且 ntp 是矫枉过正的。只要你的时间或多或少是最新的,你就会没事的。

您的代码 运行s,然后在一小时后失败 "invalid grant"。这意味着某些东西正在尝试使用刷新令牌生成新的访问令牌并失败。如果您正在执行自己的刷新,显然要检查您是否正确检索和使用刷新令牌。我的猜测是您依赖 Google python 库来执行此操作(呃,我讨厌库,哈哈)。

所以,对我来说最可能的原因是:-

  1. 刷新令牌未正确保存和恢复以用于刷新
  2. 刷新令牌已过时(即超过 25 个旧刷新令牌)。如果您 运行 在开发过程中重复测试,就会发生这种情况。始终确保您使用的是最新的 RT。
  3. 刷新令牌为空,因为它仅在用户首次授权您的应用程序时提供。尝试进入 https://myaccount.google.com/permissions?pli=1 并删除对您的应用程序的权限,然后重新开始。

如果能捕捉到http trace,对调试会有很大帮助。查看 python 库是否有任何可以打开的 debug/log 功能(我知道 Java 库有)。