Gmail API OAuth2 Error: redirect_uri_mismatch

Gmail API OAuth2 Error: redirect_uri_mismatch

我遵循了这个 Gmail API Python 快速入门教程: https://developers.google.com/gmail/api/quickstart/python

我按照说明在 API 控制台中配置了我的 OAuth 客户端 ID(请参见下面的第一张图片)。但是,启动脚本会打开一个浏览器会话,导致下面的 400 错误。

重定向 URL 与 API 控制台中注册的匹配。

但是,快速启动脚本会打开以下 URL: https://accounts.google.com/o/oauth2...&redirect_uri=http%3A%2F%2Flocalhost%3A8080%2F...

手动将重定向 URI 更改为 http://localhost:8080 部分解决了我进行授权请求时的问题,但响应无法返回到命令提示符。

如何强制快速启动程序生成 URL,将重定向 URI 保留为 http://localhost:8080

您收到错误的原因是 Python Quickstart 说:

d。 Select 凭据选项卡,单击创建凭据按钮和 select OAuth 客户端 ID。

e。 Select 应用程序类型 其他,输入名称 "Gmail API Quickstart",然后单击“创建”按钮。

但是,看看您在做什么,您使用的是 Web 应用程序 而不是 其他

当我使用其他作为client_secret.json时,我没有遇到这个问题。

结果:

The authentication flow has completed.

不需要 hacks/workaround。只需按照说明操作即可:)

说明

发生这种情况是因为传递给 Google API 服务器的 uri_redirect 参数是百分比编码的 ASCII 字符串。这可以通过查看脚本启动的 URL 来验证:

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

整个 URL 在执行此行之后的步骤中由快速启动脚本编码:

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

使用调试器逐步完成该过程显示 URL 最终使用 Python 的 urllib 库中的 urlencode 方法进行编码。这导致 client_secret.json 文件中的 redirect_uri 参数转换自:

http://localhost:8080

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

当 Google 收到 OAuth 请求时,它会将 encoded uri_redirect 参数与 un-encoded 一个在 API 控制台中注册。由于它们不匹配,因此返回 redirect_uri_mismatch。

解决方案

理想情况下,Google 应该修改 API 端点以确保在必要时解码此参数,然后再将其与 API 控制台中注册的内容进行比较。

如果 API 控制台接受编码的重定向 URI 条目,但它不接受:

解决方法(警告:hacky)

简单地替换oauth2client库中两个地方编码的redirect_uri参数:

(1) update_query_params _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_exchangeclient.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)
...

现在一切正常。