如何避免“无法检索访问令牌:{“错误";:“invalid_grant"}' 在离线 GAE cron 任务中? [英] How to avoid 'Failed to retrieve access token: { "error" : "invalid_grant" }' in offline GAE cron tasks?
问题描述
这篇文章是对如何在 GAE/Python 上进行access_type=offline"/仅限服务器的 OAuth2 操作.http = credentials.authorize(httplib2.Http())
部分在测试时不再失败,但它似乎在 GAE 的 cron 运行时仍然失败,它无法刷新我的 access_token代码>:
- 我可以通过调用
/fetch
手动运行我的工作,比如在 11:45. - 在 11:55 立即安排
/cronfetch
作业,然后,没有任何access_token
问题. 但是,我今天早上醒来看到 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 1,SO 发布 2,SO 发布 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
对象有一个空的刷新令牌,即
如如何在 GAE/Python 上进行access_type=offline"/仅限服务器的 OAuth2 操作?:
<块引用>如果用户已授权您的客户端 ID,那么您随后为这些用户执行 OAuth 时,他们将不会看到 OAuth 对话框,您也不会获得刷新令牌.
您需要确保您的 Credentials
与有效的刷新令牌一起存储,并且执行此操作的最简单方法,如您在上一个问题以及您链接到的所有 3 个问题中所述在创建您的 OAuth2WebServerFlow
或 OAuth2Decorator
对象(无论您使用的是哪个)时,请使用 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
:
- I can manually run my job by calling
/fetch
, say at 11:45. - Scheduling immediately a
/cronfetch
job at 11:55 works then, without anyaccess_token
issue. 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屋!