26

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

400 错误请求

{错误:“unauthorized_client”}

从 Google 令牌 URI:

{
  "error" : "invalid_request"
}

我在这里阅读了这个答案和谷歌官方文档(描述了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();

有什么不对的吗?

4

4 回答 4

43

问题说明

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

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

解决方案

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

游乐场设置

并输入您的客户 ID 和密码。但是,在您这样做之前,正如它所说的那样,您需要转到Developer's Console,找到您的OAuth 2.0 客户端 ID客户端,对其进行编辑并在Authorized redirect URIs下添加https://developers.google.com/oauthplayground。添加并保存更改后,返回 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)
于 2017-01-09T20:55:43.817 回答
15

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

于 2012-12-18T19:08:48.417 回答
0

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

import requests
import json

# according to  https://stackoverflow.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)
于 2018-08-10T21:00:12.553 回答
0

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

无法在服务器端刷新 Google Calendar API 的访问令牌

于 2018-10-24T18:39:02.237 回答