刷新访问令牌时出现“invalid_grant”错误的情况是什么?

4

最近我一直在苦恼这个问题。

背景:

  • 使用oauth2client库来管理用户的令牌。这些令牌会被用来执行各种后台任务,而且还会同时周期性地运行。
  • 每次要为一个用户运行其中之一任务时,我们都会从存储中获取Credentials对象,并在过期时间快到的时候进行刷新。否则就重复使用当前访问令牌。
  • 有时候,同一个用户的多个任务会同时运行。
  • 一段时间内,一切都很正常,令牌会被正常刷新。
  • 间歇性地,似乎突然出现了一个"invalid_grant"错误,并且完全废除了存储中的刷新令牌。(关于什么时候/如何/为什么会出现这种情况是我希望通过这个问题弄清楚的。)

搜索一下,就会发现有很多与此问题有关的线程/报告。但是迄今为止,我找到的所有内容都不适用于我们的情况。我会尝试列出我迄今为止研究过的内容:

  1. 用户已撤销权限

这是最明显的,并且是最有文献记录的,也很容易重现的问题。但不幸地是,在我们的情况下,我们的用户(或者在测试过程中的我们自己)根本没有撤销权限。

  1. 刷新一个"旧"访问令牌

起初我认为每个用户同时只能有一个有效的访问令牌。 但这是错误的,并且在OAuth2 Playground上进行了验证。

  1. 用户拥有太多的活动访问令牌

每个用户每个客户端最多有25个活动访问令牌的限制。一旦达到该限制,即使它们的到期日期还没有过期,旧的访问令牌也会被静默地废止。

对于我们来说,这是死胡同,因为我们的问题发生在刷新时,而不是使用最旧的访问令牌。而且这个限制只影响访问令牌,而不是刷新令牌。

  1. 在短时间内请求刷新太多次

一点都没有文献记录。只是随便提到,没有参考文献。尝试模拟在7秒内刷新25次,但是所有步骤都进行得很顺利。但由于没有参考文献,这只是一个盲目的猜测。而且我们的后台任务只能最多每几分钟运行一次10个任务。我们继续寻找原因。

  1. 并发刷新导致竞争条件,无法确定哪个令牌会成功

我已经在这里提出了一个问题,但这不是情况。通过同时运行两个任务来测试在AppEngine上。


我已经快要绝望地试图解决这个问题。我们无法轻易地重现它是一种痛苦。我真的很想知道可能导致这种问题的见解,但我错过了什么?

这是我们的刷新代码:

def refresh_oauth_credentials(user, credentials, force=False):
    if not credentials:
        return None
    logging.debug(credentials.token_expiry)
    do_refresh = credentials._expires_in() < 300
    if force or do_refresh:
        h = httplib2.Http()
        try:
            logging.debug('Refreshing %s\'s oauth2 credentials...' % user.email)
            credentials.refresh(h)
        except AccessTokenRefreshError:
            logging.warning('Failed to refresh.')
            return None
    return credentials
1个回答

1
这条消息基本上是在说刷新令牌无效(已过期、被撤销等)或与访问令牌请求详细信息(用户、范围)不匹配。因此,在您的问题中提到“返回了一个“invalid_grant”错误,并且它完全使存储中的刷新令牌无效”时,实际上是反过来的,也就是说,刷新令牌由于某种原因无效,这导致了“无效授权”。在开发过程中,如果在开发工作流/测试期间为用户获取新的刷新令牌,则会经常看到这种情况。

经过仔细检查(和大量记录),似乎OAuth2回调有时不包括刷新令牌。由于我假设如果正确的参数提供给了Dance,就会始终提供刷新令牌,因此我盲目地覆盖了存储的令牌。我将发起一个新问题,以了解为什么有时没有获取到刷新令牌。 - john2x

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接