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

时间:2012-12-14 02:54:15

标签: google-api oauth-2.0 google-api-java-client

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

  

400错误请求

     

{error:“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();

有什么不对吗?

4 个答案:

答案 0 :(得分:19)

问题解释

通过提示@MartinV,我终于能够解决它了!因为他的答案并不能很好地解释如何解决它,所以我将在这里发布。

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

<强>解

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

Playground settings

输入您的客户ID和密码。但是,在您这样做之前,您需要转到Developer's Console,找到 OAuth 2.0客户端ID 客户端,编辑它并添加 {{3} 授权重定向URI 下的。添加并保存更改后,返回操场并尝试授权API。在我的情况下,在授权重定向URI 的更改生效之前花了15分钟。

完成后,请勿忘记从开发者控制台中删除Playground URI!

<强> EXTRA

一旦我这样做了,在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)

答案 1 :(得分:10)

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

答案 2 :(得分:0)

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

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)

答案 3 :(得分:0)

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

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