首页 文章

Gmail API OAuth2错误:redirect_uri_mismatch

提问于
浏览
0

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

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

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

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

手动将重定向URI更改为http://localhost:8080部分修复了问题,因为我继续执行授权请求,但随后响应无法返回到命令提示符 .

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

Google API console

400 Error

2 回答

  • 0

    你得到错误的原因是Python Quickstart说:

    d . 选择“凭据”选项卡,单击“创建凭据”按钮,然后选择“OAuth客户端ID” .

    e . 选择应用程序类型 Other ,输入名称"Gmail API Quickstart",然后单击“创建”按钮 .

    但是,看看你正在做什么,你使用 Web Application 而不是 Other .

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

    result

    身份验证流程已完成 .

    不需要黑客/解决方法 . 按照说明:)

  • 2

    Explanation

    发生这种情况是因为传递给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参数与API控制台中注册的 un-encoded 进行比较 . 由于它们不匹配,因此返回redirect_uri_mismatch .

    Solution

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

    如果API控制台接受编码的重定向URI条目,则可接受的修复方法是,但它不会:

    enter image description here

    Workaround (警告:hacky)

    只需在oauth2client库中的两个位置替换编码的redirect_uri参数:

    (1)_helpers.py中的update_query_params函数

    ...
    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)client.py中的step2_exchange_

    ...
            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)
    ...
    

    现在一切正常 .

相关问题