无法刷新访问令牌:响应为“unauthorized_client”

Posted

技术标签:

【中文标题】无法刷新访问令牌:响应为“unauthorized_client”【英文标题】:Unable to refresh access token : response is "unauthorized_client" 【发布时间】:2012-12-02 01:25:16 【问题描述】:

当我尝试刷新访问令牌时出现错误:

400 错误请求

错误:“unauthorized_client”

来自 Google 令牌 URI:


  "error" : "invalid_request"

我阅读了这个答案 here 和 Google 官方文档(描述了 POST 请求的外观),我没有发现任何区别。

我捕获了我的POST 请求(已删除秘密):

POST /SHOWMERAWPOST HTTP/1.1
User-Agent: Google-HTTP-Java-Client/1.10.3-beta (gzip)
Pragma: no-cache
Host: requestb.in
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
Content-Length: 175
Connection: keep-alive
Cache-Control: no-cache
Accept-Encoding: gzip
Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2

grant_type=refresh_token&refresh_token=******&client_id=*******.apps.googleusercontent.com&client_secret=******

发送请求的Java代码:

RefreshTokenRequest req = new RefreshTokenRequest(new NetHttpTransport(), new JacksonFactory(), new GenericUrl(
                    getSecrets().getDetails().getTokenUri()), REFRESH_TOKEN);

           req.set("client_id", getSecrets().getDetails().getClientId());
           req.set("client_secret", getSecrets().getDetails().getClientSecret());

           TokenResponse response = req.execute();

有什么问题吗?

【问题讨论】:

你找到答案了吗,得到同样的错误 (***.com/questions/13878605/…) 我不需要模拟用户,我只发送带有刷新令牌的客户端和秘密 ID。那是不同的情况。 【参考方案1】:

问题说明

在@MartinV 的提示下,我终于能够修复它!因为他的回答并没有很好地解释如何解决它,所以我将其发布在这里。

问题是因为我们都使用Google's OAuth Playground 生成了刷新令牌,但是当您在第一步中单击“授权 API”时,它会将您带到使用 Playground 应用程序的集中屏幕。之后,您创建的所有令牌只能由 Playground 应用程序使用,但您当然不知道该应用程序的客户端 ID 或客户端密码。

解决方案

解决方案是让 Playground 使用您自己的 Client ID 和 Secret。为此,请单击“设置”按钮:

然后输入您的客户 ID 和密码。但是,在你这样做之前,正如它所说的那样,你需要去Developer's Console,找到你的OAuth 2.0 客户端ID客户端,编辑它并添加https://developers.google.com/oauthplayground授权的重定向 URIs 下。添加并保存更改后,返回 Playground 并尝试授权 API。就我而言,授权重定向 URI 中的更改大约需要 15 分钟才能生效。

完成后,别忘了从开发者控制台中删除 Playground URI!

额外

一旦我这样做了,我在 Python 中就这样做了,并且成功了:

access_token = None 
client_id = 'xxxxxxxx.apps.googleusercontent.com'
client_secret = 'xxxxxxxxxxxx'
refresh_token = 'xxxxxxxxxxxx'
token_expiry = None
token_uri = "https://accounts.google.com/o/oauth2/token"
user_agent = 'YourAgent/1.0'

credentials = client.GoogleCredentials(access_token, client_id, client_secret, refresh_token, token_expiry, token_uri, user_agent)

http = credentials.authorize(httplib2.Http())
credentials.refresh(http)

service = build('drive', 'v3', http=http)
req = service.files().list()
resp = req.execute(http=http)

【讨论】:

我已按照您的所有步骤操作,但在完成整个过程后,当我在 oauthplayground 中获得访问令牌时,refresh_token 为空白。 不确定我是否理解。在 Playground 中,您需要点击兑换令牌的授权码来获取刷新令牌。 我尝试在本地主机上进行测试,并将我的重定向 uri 设置为操场,但我在本地主机服务器中得到:“redirect_uri_mismatch” 天啊!谢谢!!!!....在查看了大量有关该主题的 *** 帖子,查看了有关一般主题的多个教程并拔出我的头发一周 + 试图弄清楚为什么我的刷新令牌的编程请求失败......这似乎解决了这个问题。我同意@user1701153 的观点,即 Google 需要更好的文档……这真的太可怕了!啊! 天哪!我与这个问题斗争了好几天,直到我找到了这篇文章。谢谢你,这应该被接受的答案!!! @google 请更新您的文档。这不正常!【参考方案2】:

我在 OAuth2 Playground 中创建了访问和刷新令牌,然后将它们复制到我的应用程序中。 授权和令牌刷新不允许有不同的客户端。

【讨论】:

不允许有不同的客户端进行自动化和令牌刷新>>马丁你能解释一下吗..我面临类似的问题..谢谢。 嗨,马丁,请告诉我您为解决此错误所做的工作。我也面临同样的问题。 请定义什么是客户端...IP地址,用户代理,它是怎么知道的? 当您使用刷新令牌时会出现此问题,该令牌由 [clientid,screretid] 生成,它不同于 [clientid,screretid] 用于授权过程。【参考方案3】:

另一种解决方案使用 REST API 获取 access_token,然后在创建 refresh_token 后使用它与 REST API 交互(例如,将视频添加到私有播放列表),如 above 所述。

import requests
import json

# according to  https://***.com/a/41556775/3774227
client_id = '<client_id>'
client_secret = '<client_secret>'
refresh_token = '<refresh_token>'

playlist_id = '<playlist>'
video_id = 'M7FIvfx5J10'


def get_access_token(client_id, client_secret, refresh_token):

    url = 'https://www.googleapis.com/oauth2/v4/token'

    data = 
        'client_id': client_id,
        'client_secret': client_secret,
        'refresh_token': refresh_token,
        'grant_type': 'refresh_token'
    

    response = requests.post(
        url=url,
        data=data,
    )

    return response.json().get('access_token')


def add_video_to_playlist(playlist_id, video_id, access_token):

    url = 'https://www.googleapis.com/youtube/v3/playlistItems'

    params = 
        'part': 'snippet',
    

    headers = 
        'Content-Type': 'application/json',
        'Authorization': 'Bearer '.format(access_token)
    

    data = 
        'snippet': 
            'playlistId': playlist_id,
            'resourceId': 
                'kind': 'youtube#video',
                'videoId': video_id
            ,
        
    

    requests.post(
        url=url,
        params=params,
        headers=headers,
        data=json.dumps(data)
    )


if __name__ == '__main__':
    access_token = get_access_token(client_id, client_secret, refresh_token)
    add_video_to_playlist(playlist_id, video_id, access_token)

【讨论】:

【参考方案4】:

我遇到了同样的问题。解决方案是在应用程序中授权和更新服务器上的令牌时使用相同的客户端。

Can't refresh access token for Google Calendar API on server side

【讨论】:

以上是关于无法刷新访问令牌:响应为“unauthorized_client”的主要内容,如果未能解决你的问题,请参考以下文章

IdentityServer4 刷新令牌为空

刷新谷歌访问令牌时未授权_客户端

无法使用 OAuth 1.0a 授权我,请求访问令牌时失败

Spring oauth2 刷新令牌 - 无法将访问令牌转换为 JSON

Spring oauth2刷新令牌 - 无法将访问令牌转换为JSON

Angular 4 和 OAuth - 拦截 401 响应,刷新访问令牌并重试请求