Golang集成Azure AD OAuth2换取Token返回401 Unauthorized错误
Azure AD OAuth2 回调报401错误修复
问题现象
- 已确认client id、client secret配置正确,回调地址设为
http://localhost:8080/callback,Azure AD后台已启用公共客户端流 - 运行
main.go可正常加载登录页,输入邮箱密码完成身份认证后,跳转回调地址时报错:Handler error: token response was 401 Unauthorized


问题原因
手动构造令牌请求的代码存在多处错误,导致Azure AD令牌端点拒绝请求:
- 核心参数缺失:授权码流程换token必须携带回调请求返回的
code参数、已配置的client_secret参数,代码中完全没有传递这两个字段 - 参数编码错误:手动对
scope、redirect_uri做了URL编码,但url.Values.Encode()方法本身会自动执行URL编码,造成双重编码后参数值不符合要求 - 参数冗余/不匹配:硬编码
state=12345,和授权阶段生成的state值不一致;额外传递了仅授权阶段需要的response_type、response_mode参数,令牌端点不需要这两个字段 - 端点配置风险:
AuthURL中租户ID占位符首字母大写,TokenURL中占位符全小写,实际替换时如果大小写不一致会直接请求到错误的端点 - 重复造轮子:
golang.org/x/oauth2已经封装了标准OAuth2流程的令牌交换逻辑,手动构造请求极易出现参数遗漏、格式错误问题
修复步骤
1. 修正OAuth2基础配置
统一租户ID写法,补充所需权限范围,建议使用v2.0版本端点兼容性更好:
config = &oauth2.Config{ ClientID: "<替换为实际client id>", ClientSecret: "<替换为实际client secret,公共客户端可留空>", RedirectURL: redirectURI, Endpoint: oauth2.Endpoint{ AuthURL: "https://login.microsoftonline.com/<替换为实际租户ID,统一小写>/oauth2/v2.0/authorize", TokenURL: "https://login.microsoftonline.com/<替换为和上方完全一致的租户ID>/oauth2/v2.0/token", }, Scopes: []string{"openid", "profile", "offline_access", "User.Read"}, }
2. 重写回调处理逻辑
删除手动构造HTTP请求换token的代码,直接调用oauth2库内置的Exchange方法,该方法会自动处理参数拼接、编码、请求发送全流程:
func CallbackHandler(w http.ResponseWriter, req *http.Request) error { session, _ := store.Get(req, "session") // 校验state防CSRF if req.FormValue("state") != SessionState(session) { return Error{http.StatusBadRequest, "invalid callback state"} } // 从回调参数中取授权码 code := req.FormValue("code") if code == "" { return Error{http.StatusBadRequest, "missing authorization code"} } // 调用库方法交换令牌 token, err := config.Exchange(req.Context(), code) if err != nil { return fmt.Errorf("token exchange failed: %v", err) } // 令牌存入session session.Values["token"] = token if err := session.Save(req, w); err != nil { return fmt.Errorf("error saving session: %v", err) } http.Redirect(w, req, "/", http.StatusFound) return nil }
3. 核对Azure AD后台配置
- 重定向URI类型选择
Web,值精确为http://localhost:8080/callback,末尾不要加斜杠 - 若使用公共客户端模式,确认后台已开启「将应用程序视为公共客户端」开关,同时配置中
ClientSecret留空 - 确认已为应用授予
Microsoft Graph -> User.Read委托权限
验证
重新运行程序,完成登录后即可正常跳转回首页,调用Graph接口获取用户信息。
内容的提问来源于stack exchange,提问作者omkar
相关产品推荐
相关产品推荐

