如何避免“无法检索访问令牌:{“错误";:“invalid_grant"}' 在离线 GAE cron 任务中? [英] How to avoid 'Failed to retrieve access token: { "error" : "invalid_grant" }' in offline GAE cron tasks?

查看:34
本文介绍了如何避免“无法检索访问令牌:{“错误";:“invalid_grant"}' 在离线 GAE cron 任务中?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这篇文章是对如何在 GAE/Python 上进行access_type=offline"/仅限服务器的 OAuth2 操作.http = credentials.authorize(httplib2.Http()) 部分在测试时不再失败,但它似乎在 GAE 的 cron 运行时仍然失败,它无法刷新我的 access_token:

  1. 我可以通过调用 /fetch 手动运行我的工作,比如在 11:45.
  2. 在 11:55 立即安排 /cronfetch 作业,然后,没有任何 access_token 问题.
  3. 但是,我今天早上醒来看到 same /cronfetch 任务(除了时间之外相同,对于我的非- 测试日常任务)失败:

    I 2013-06-10 05:53:51.324 make: Got type <class 'google.appengine.api.datastore_types.Blob'>我 2013-06-10 05:53:51.325 验证:得到类型 <class 'oauth2client.client.OAuth2Credentials'>我 2013-06-10 05:53:51.327 URL 被请求:https://www.googleapis.com/youtube/v3/playlists?alt=json&part=snippet%2CstatusI 2013-06-10 05:53:51.397 由于 401 刷新I 2013-06-10 05:53:51.420 make: Got type <class 'google.appengine.api.datastore_types.Blob'>我 2013-06-10 05:53:51.421 验证:得到类型 <class 'oauth2client.client.OAuth2Credentials'>I 2013-06-10 05:53:51.421 刷新 access_token我 2013-06-10 05:53:51.458 无法检索访问令牌:{错误":invalid_grant"}I 2013-06-10 05:53:51.468 make: Got type <class 'google.appengine.api.datastore_types.Blob'>我 2013-06-10 05:53:51.468 验证:得到类型 <class 'oauth2client.client.OAuth2Credentials'>我 2013-06-10 05:53:51.471 验证:得到类型 <class 'oauth2client.client.OAuth2Credentials'>我 2013-06-10 05:53:51.471 得到:得到类型 <class 'oauth2client.appengine.CredentialsModel'>E 2013-06-10 05:53:51.480 invalid_grant Traceback(最近一次调用最后一次):文件/python27_runtime/python27_lib/versions/third_party/webapp2-2.5.2/webapp2.py",第 1535 行,在

这个 出现invalid_grant"错误令牌刷新邮件列表消息(+ SO post 1SO 发布 2SO 发布 3) 看起来与我的问题相似,但它似乎发生在 access_type=online 令牌上.在我的情况下,我只使用默认的 access_type=offline,并且在初始访问请求中看到 当我不使用应用程序时执行这些操作" 提到.

我刚刚重新安排了 08:25 的 cron 运行(注意不要启动手动),并使用我为您提交给 GitHub 的调试打印语句.这是我得到的,它相似但不完全相同(注意最后几行的顺序似乎不正确,在读取所有源之前,我绝对不会在 create_playlist 中执行 OAuth2 内容).因此,忽略倾斜顺序(GAE 日志记录工件?),似乎 我在 create_playlist(self) 中的 http = credentials.authorize(Http()) 调用,目前在第 144 行 是错误的:

<代码> ...E 2013-06-10 08:26:12.817 http://www.onedayonemusic.com/page/2/: 发现嵌入 ['80wWl_s-HuQ', 'kb1Nu75l1vA', 'kb1Nu75l1vA', 'kb1Nu75l1vA', 'tQtwEwNRQ', 'ZtDXezAhes8', 'ZtDXezAhes8', 'cFGxNJhKK9c', 'cFGxNJhKK9c'I 2013-06-10 08:26:14.019 make: Got type <class 'google.appengine.api.datastore_types.Blob'>我 2013-06-10 08:26:14.020 验证:得到类型 <class 'oauth2client.client.OAuth2Credentials'>我 2013-06-10 08:26:14.022 URL 被请求:https://www.googleapis.com/youtube/v3/playlists?alt=json&part=snippet%2CstatusI 2013-06-10 08:26:14.100 由于 401 刷新I 2013-06-10 08:26:14.105 make: Got type <class 'google.appengine.api.datastore_types.Blob'>我 2013-06-10 08:26:14.106 验证:得到类型 <class 'oauth2client.client.OAuth2Credentials'>I 2013-06-10 08:26:14.106 刷新 access_tokenE 2013-06-10 08:26:18.994 等待来自 URL 的 HTTP 响应时超出了截止日期:https://accounts.google.com/o/oauth2/token Traceback(最近一次调用):文件/pytE 2013-06-10 08:26:18.996 http://www.onedayonemusic.com/page/3/: 发现嵌入 ['80wWl_s-HuQ', '6VNu2MLdE0c', '6VNu2MLdE0c', 'YwKYkQilk',, 'KYdB3rectmc', 'KYdB3E 2013-06-10 08:26:18.996 crawl_videos 结束E 2013-06-10 08:26:18.996 create_playlist 开始E 2013-06-10 08:26:18.996 create_playlist 获得了信用E 2013-06-10 08:26:18.996 create_playlist 授权凭证

→为什么 cron 作业在手动运行 5 分钟后工作,但在 6 小时后失败?我认为刷新令牌永远不会过期.我究竟做错了什么?

请注意,这是我的第一个 GAE 工作,也是我的第二个 Python 程序,非常欢迎一般的代码审查/建议,但请保持温和:)

代码位于 GitHub 上,我的实例可以通过 dailygrooves.org.感谢您的帮助!

解决方案

当刷新令牌不能用于从当前用户获取新的访问令牌时,返回一个 invalid_grant.这是因为存储的 Credentials 对象有一个空的刷新令牌,即

<预><代码>>>>credentials.refresh_token 是 None真的

如何在 GAE/Python 上进行access_type=offline"/仅限服务器的 OAuth2 操作?:

<块引用>

如果用户已授权您的客户端 ID,那么您随后为这些用户执行 OAuth 时,他们将不会看到 OAuth 对话框,您也不会获得刷新令牌.

您需要确保您的 Credentials 与有效的刷新令牌一起存储,并且执行此操作的最简单方法,如您在上一个问题以及您链接到的所有 3 个问题中所述在创建您的 OAuth2WebServerFlowOAuth2Decorator 对象(无论您使用的是哪个)时,请使用 approval_prompt=force.

This post is a followup to How to make 'access_type=offline' / server-only OAuth2 operations on GAE/Python. The http = credentials.authorize(httplib2.Http()) part no longer fails when testing, but it seems it still does when run by GAE's cron, where it's unable to refresh my access_token :

  1. I can manually run my job by calling /fetch, say at 11:45.
  2. Scheduling immediately a /cronfetch job at 11:55 works then, without any access_token issue.
  3. But then, I woke up this morning seeing that the same /cronfetch task (same except the timing, which is at 01:00 for my non-test daily task) failed:

    I 2013-06-10 05:53:51.324 make: Got type <class 'google.appengine.api.datastore_types.Blob'>
    I 2013-06-10 05:53:51.325 validate: Got type <class 'oauth2client.client.OAuth2Credentials'>
    I 2013-06-10 05:53:51.327 URL being requested: https://www.googleapis.com/youtube/v3/playlists?alt=json&part=snippet%2Cstatus
    I 2013-06-10 05:53:51.397 Refreshing due to a 401
    I 2013-06-10 05:53:51.420 make: Got type <class 'google.appengine.api.datastore_types.Blob'>
    I 2013-06-10 05:53:51.421 validate: Got type <class 'oauth2client.client.OAuth2Credentials'>
    I 2013-06-10 05:53:51.421 Refreshing access_token
    I 2013-06-10 05:53:51.458 Failed to retrieve access token: { "error" : "invalid_grant" }
    I 2013-06-10 05:53:51.468 make: Got type <class 'google.appengine.api.datastore_types.Blob'>
    I 2013-06-10 05:53:51.468 validate: Got type <class 'oauth2client.client.OAuth2Credentials'>
    I 2013-06-10 05:53:51.471 validate: Got type <class 'oauth2client.client.OAuth2Credentials'>
    I 2013-06-10 05:53:51.471 get: Got type <class 'oauth2client.appengine.CredentialsModel'>
    E 2013-06-10 05:53:51.480 invalid_grant Traceback (most recent call last): File "/python27_runtime/python27_lib/versions/third_party/webapp2-2.5.2/webapp2.py", line 1535, in
    

This Getting "invalid_grant" error on token refresh mailing list message (+ SO post 1, SO post 2, SO post 3) look similar to my problem, but it seems to be happening with a access_type=online token. In my case I just use the default access_type=offline, and I see the "Perform these operations when I'm not using the application" mention in the initial access request.

I just re-scheduled a cron run at 08:25 (taking care not to launch a manual one) with debug print statements that I committed to GitHub for you. Here is what I get, it is similar but not identical (Note the few last lines seem ordered incorrectly, I definitely am not doing OAuth2 stuff in create_playlist until all sources are read). So ignoring the skewed order (GAE logging artifact?), it seems my http = credentials.authorize(Http()) call in create_playlist(self), currently at line 144 is wrong:

    ...
    E 2013-06-10 08:26:12.817 http://www.onedayonemusic.com/page/2/ : found embeds ['80wWl_s-HuQ', 'kb1Nu75l1vA', 'kb1Nu75l1vA', 'RTWcNRQtkwE', 'RTWcNRQtkwE', 'ZtDXezAhes8', 'ZtDXezAhes8', 'cFGxNJhKK9c', 'cFGxNJhKK9c'
    I 2013-06-10 08:26:14.019 make: Got type <class 'google.appengine.api.datastore_types.Blob'>
    I 2013-06-10 08:26:14.020 validate: Got type <class 'oauth2client.client.OAuth2Credentials'>
    I 2013-06-10 08:26:14.022 URL being requested: https://www.googleapis.com/youtube/v3/playlists?alt=json&part=snippet%2Cstatus
    I 2013-06-10 08:26:14.100 Refreshing due to a 401
    I 2013-06-10 08:26:14.105 make: Got type <class 'google.appengine.api.datastore_types.Blob'>
    I 2013-06-10 08:26:14.106 validate: Got type <class 'oauth2client.client.OAuth2Credentials'>
    I 2013-06-10 08:26:14.106 Refreshing access_token
    E 2013-06-10 08:26:18.994 Deadline exceeded while waiting for HTTP response from URL: https://accounts.google.com/o/oauth2/token Traceback (most recent call last): File "/pyt
    E 2013-06-10 08:26:18.996 http://www.onedayonemusic.com/page/3/ : found embeds ['80wWl_s-HuQ', '6VNu2MLdE0c', '6VNu2MLdE0c', 'YwQilKbK9Mk', 'YwQilKbK9Mk', 'KYdB3rectmc', 'KYdB3
    E 2013-06-10 08:26:18.996 crawl_videos end
    E 2013-06-10 08:26:18.996 create_playlist start
    E 2013-06-10 08:26:18.996 create_playlist got creds
    E 2013-06-10 08:26:18.996 create_playlist authorized creds

→ Why does the cron job work 5min after a manual run, but fails 6hours later? I thought the refresh token never expired. What am I doing wrong?

Note that's my first GAE work, and my second Python program at all, general code review/advice is very welcome but please be gentle :)

The code is on GitHub and my instance can be reached at dailygrooves.org. Thanks for your help!

解决方案

An invalid_grant is returned when the refresh token can't be used to get a new access token from the current user. This is happening to you because the stored Credentials object has a null refresh token, i.e.

>>> credentials.refresh_token is None
True

As mentioned in the NOTE in How to make 'access_type=offline' / server-only OAuth2 operations on GAE/Python?:

If a user has already authorized your client ID, the subsequent times you perform OAuth for these users they will not see the OAuth dialog and you won't be given a refresh token.

You need to make sure your Credentials are stored with a valid refresh token and the easiest way to do this, as mentioned in your last question as well as in all 3 questions you linked to is to use approval_prompt=force when creating your OAuth2WebServerFlow or OAuth2Decorator object (whichever you are using).

这篇关于如何避免“无法检索访问令牌:{“错误";:“invalid_grant"}' 在离线 GAE cron 任务中?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆