Unable to refresh access token : response is “unauthorized_client”

流过昼夜 提交于 2019-11-30 08:34:03

PROBLEM EXPLANATION

With the hint @MartinV gave I was finally able to fix it! Because his answer doesn't explain very well how to solve it, I'm going to post it here.

The problem is because we all have generated the Refresh Token using Google's OAuth Playground, but when you click 'Authorize APIs' in the first step, it takes you to the concent screen using the Playground app. After that, all the tokens that you create can be used only by the Playground app, but of course you don't know either the Client ID or the Client Secret for that app.

SOLUTION

The solution is to make Playground to use your own Client ID and Secret. To do so, click on the Settings button:

And enter your Client ID and Secret. But, before you do that, as it says there, you need to go to the Developer's Console, find your OAuth 2.0 client IDs client, edit it and add https://developers.google.com/oauthplayground under Authorized redirect URIs. After you added that and saved the changes, go back to the playground and try to Authorize APIs. In my case it took like 15 minutes before the changes in the Authorized redirect URIs took effect.

Once you're done, don't forget to remove the Playground URI from the Developer Console!

EXTRA

Once I have done that, in Python I did this and it worked:

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)

I created access and refresh token in OAuth2 playground and then i copied them to my app. It`s not allowed to have different clients for autorization and for token refresh.

Another solution using the REST API to get an access_token and then use it to interact with the REST API (e.g. add a video to a private playlist) after creating the refresh_token as described above.

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)

I had the same problem. The solution was to use the same client when authorizing in the application and when updating the token on the server.

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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!