Django集成Google日历InstalledAppFlow报redirect_uri_mismatch错误
你使用了错误的OAuth授权流类型。InstalledAppFlow是Google OAuth SDK面向桌面端、命令行、移动端等本地安装应用设计的授权流,运行时会自动拼接已安装应用专属的回调地址(比如本地环回地址、OOB回调地址),和你Django服务配置的回调地址完全不匹配,必然触发redirect_uri_mismatch错误。你手动拼接授权URL时自行传入了正确的回调地址,绕过了SDK自动生成错误回调的逻辑,因此可以正常完成授权。
替换授权流实现
移除代码中对InstalledAppFlow的调用,改用Web服务场景专用的Flow类完成授权逻辑,参考实现如下:from google_auth_oauthlib.flow import Flow # 加载客户端密钥配置,初始化Web端授权流 flow = Flow.from_client_secrets_file( client_secrets_path, # 替换为你的client_secret.json实际路径 scopes=["https://www.googleapis.com/auth/calendar"], # 按需调整日历权限范围 redirect_uri="你的Django项目实际使用的回调完整地址" ) # 生成授权跳转地址,同时生成state参数用于CSRF校验 auth_url, state = flow.authorization_url( access_type="offline", # 需要刷新令牌就加这个配置 include_granted_scopes=True, prompt="consent" ) # 将state存入当前用户session后,重定向到auth_url即可进入Google授权页 request.session["google_oauth_state"] = state return redirect(auth_url)回调视图中拿到授权码后,直接调用
flow.fetch_token()即可完成令牌换取,不要调用InstalledAppFlow自带的run_local_server()方法,该方法仅用于本地桌面应用临时启动服务接收授权码,不适用于Web服务场景。逐字符核对回调地址一致性
Google对回调地址执行严格的逐字符匹配校验,只要请求中携带的redirect_uri和GCP控制台配置的已授权重定向URI有任何字符差异,就会触发该错误,核对时注意以下细节:- 协议头必须完全匹配:本地调试用
http就不能填https,线上用https就不能填http - 域名、端口必须完全匹配:本地调试用
localhost:8000就不能填127.0.0.1:8000,非80/443端口必须显式写在地址里 - 路径必须完全匹配:路由末尾带斜杠就不能漏,比如回调路由是
/oauth/google/callback/,就不能配置成/oauth/google/callback - 不要在回调地址后追加多余的查询参数、片段标识符
你手动拼接URL时能正常授权,说明你当时用的回调地址本身是合法的,把这个地址原封不动传入Flow的redirect_uri参数,同时添加到GCP控制台的已授权重定向URI列表即可。
- 协议头必须完全匹配:本地调试用
排查部署场景的隐藏问题
如果是线上部署环境,额外确认反向代理(Nginx、CDN等)没有改写请求路径、没有做强制域名跳转,确保Google回调的请求能准确命中你处理OAuth回调的Django视图函数。
完成上述调整后,你可以在跳转授权页前打印生成的auth_url,提取其中的redirect_uri参数,和你之前手动拼接可用的回调地址做对比,二者完全一致且在GCP控制台已配置的情况下,就不会再出现该错误。
内容的提问来源于stack exchange,提问作者Aditya Mutharia

