Gmail API OAuth2 Error: redirect_uri_mismatch

2019-08-16 05:11发布

I followed this Gmail API Python Quickstart tutorial: https://developers.google.com/gmail/api/quickstart/python

I configured my OAuth client ID in the API console as instructed (see the first image below). However, launching the script opens a browser session that results in the 400 error below.

The redirect URL matches what is registered in the API console.

HOWEVER, the quickstart script opens the following URL: https://accounts.google.com/o/oauth2... &redirect_uri=http%3A%2F%2Flocalhost%3A8080%2F ...

Manually changing redirect URI to http://localhost:8080 partially fixes the problem as I proceed to the authorization request, but then the response can't get returned to the command prompt.

How can I force the quickstart program to produce a URL that leaves the redirect URI as http://localhost:8080?

Google API console

400 Error

2条回答
Rolldiameter
2楼-- · 2019-08-16 05:30

Explanation

This is happening because the uri_redirect parameter being passed to the Google API server is a percent encoded ASCII string. This can be verified by looking at the URL launched by the script:

...redirect_uri=http%3A%2F%2Flocalhost%3A8080%2F...

The whole URL gets encoded by the quickstart script in the steps following the execution of this line:

credentials = tools.run_flow(flow, store, flags)

Stepping through the process with a debugger reveals the URL is eventually encoded with the urlencode method from Python's urllib library. This results in the redirect_uri parameter from the client_secret.json file converting from:

http://localhost:8080

To

http%3A%2F%2Flocalhost%3A8080%2F

When Google receives the OAuth request, it compares the encoded uri_redirect parameter against the un-encoded one registered in the API console. Since they don't match, a redirect_uri_mismatch is returned.

Solution

Ideally, Google should modify the API endpoint to ensure that this parameter is decoded if necessary before comparing it to what's registered in the API console.

An acceptable fix would be if the API console would accept encoded redirect URI entries, but it does not:

enter image description here

Workaround (warning: hacky)

Simply replace the encoded redirect_uri parameter in two places in the oauth2client library:

(1) update_query_params function in _helpers.py

...
start = new_query.find("redirect_uri")+13
end = new_query.find("&",start)
new_query2 = new_query[:start] + "http://localhost:8080" + new_query[end:]

new_parts = parts._replace(query=new_query2)
...

(2) step2_exchange in client.py

...
        body = urllib.parse.urlencode(post_data)
    start = body.find("redirect_uri")+13
    end = body.find("&",start)
    body2 = body[:start] + "http://localhost:8080" + body[end:]

    headers = {
        'content-type': 'application/x-www-form-urlencoded',
    }
    if self.authorization_header is not None:
        headers['Authorization'] = self.authorization_header
    if self.user_agent is not None:
        headers['user-agent'] = self.user_agent

    if http is None:
        http = transport.get_http_object()

    resp, content = transport.request(
        http, self.token_uri, method='POST', body=body2, headers=headers)
...

Now everything works.

查看更多
爱情/是我丢掉的垃圾
3楼-- · 2019-08-16 05:39

The cause of the error you're getting is that the Python Quickstart says:

d. Select the Credentials tab, click the Create credentials button and select OAuth client ID.

e. Select the application type Other, enter the name "Gmail API Quickstart", and click the Create button.

However, looking at what you're doing, you are using Web Application instead of Other.

When I used the Other as client_secret.json, I didn't encounter this problem.

result:

The authentication flow has completed.

No hacks/workaround needed. Just follow instructions :)

查看更多
登录 后发表回答