You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何从MSAL Browser获取授权码?当前返回undefined(Microsoft Graph API)

问题解决:MSAL Browser获取授权码返回undefined的修复方案

问题根源

你代码里loginResponse.code返回undefined,是因为MSAL Browser的loginPopup方法默认会自动把授权码交换成访问令牌/ID令牌,不会把原始授权码返回给你。如果要把授权码传给后端去交换令牌(尤其是要拿到刷新令牌,前端不能存这个),得调整MSAL配置和登录逻辑。

修复步骤

1. 调整MSAL实例配置

把MSAL实例改成**授权码流(PKCE)**配置,指定返回授权码:

const msalInstance = new PublicClientApplication({
  auth: {
    clientId: "你的客户端ID",
    authority: "https://login.microsoftonline.com/common",
    redirectUri: "你的重定向地址", // 必须和Azure AD后台配置的一致
    responseType: "code" // 关键:告诉MSAL返回授权码而非直接返回令牌
  }
});

2. 修改登录逻辑,手动捕获授权码

不用loginPopup(它会自动交换令牌),改用getAuthCodeUrl生成授权链接,通过弹窗打开并捕获授权码:

const loginAndGetAuthorizationCode = async () => {
  const loginRequest = {
    scopes: ["User.Read", "Mail.Read", "offline_access"],
    redirectUri: "你的重定向地址" // 和实例配置保持一致
  };

  try {
    // 生成授权URL
    const authCodeUrl = await msalInstance.getAuthCodeUrl(loginRequest);
    
    // 打开登录弹窗
    const popupWindow = window.open(authCodeUrl, "_blank", "width=600,height=700");
    if (!popupWindow) throw new Error("无法打开登录弹窗");

    // 监听弹窗消息,获取授权码
    const authCode = await new Promise<string>((resolve, reject) => {
      const messageListener = (event: MessageEvent) => {
        if (event.source === popupWindow && event.data.type === "msal:authCode") {
          window.removeEventListener("message", messageListener);
          popupWindow.close();
          resolve(event.data.code);
        }
      };
      window.addEventListener("message", messageListener);

      // 监听弹窗关闭,处理取消登录的情况
      const interval = setInterval(() => {
        if (popupWindow.closed) {
          clearInterval(interval);
          window.removeEventListener("message", messageListener);
          reject(new Error("登录弹窗已关闭"));
        }
      }, 100);
    });

    // 把授权码传给后端
    await authorizeEmail(authCode);
    return authCode;
  } catch (error) {
    console.error("Login failed: ", error);
  }
};

3. 处理重定向页面的授权码

在你配置的redirectUri对应的页面里,要捕获授权码并传给主窗口:

// 重定向页面的代码
window.addEventListener("load", async () => {
  const msalInstance = new PublicClientApplication({
    auth: {
      clientId: "你的客户端ID",
      authority: "https://login.microsoftonline.com/common",
      redirectUri: "你的重定向地址"
    }
  });

  const result = await msalInstance.handleRedirectPromise();
  if (result && result.code) {
    // 把授权码发送给主窗口
    window.opener?.postMessage({ type: "msal:authCode", code: result.code }, "*");
  }
});

4. 修正authorizeEmail函数

确保传递的是正确的授权码(不是ID令牌):

const authorizeEmail = async (authCode: string | undefined) => {
  if (!authCode) return;
  
  // 这里的token是你自身应用的用户令牌,用于验证后端请求合法性
  const token = await getIdTokenClaims(); 
  await axios.post(
    `${process.env.BASE_URL}/email/authorize/`,
    {
      code: authCode, // 现在传的是正确的授权码
      deal_id: 22,
    },
    {
      headers: {
        'Content-Type': 'application/json',
        "Authorization": `Bearer ${token}`,
      },
    }
  );
};

关键说明

  • offline_access权限必须加:只有加了这个,后端才能拿到刷新令牌,用于后续静默刷新访问令牌。
  • PKCE是自动处理的:MSAL会自动生成验证密钥,不用你手动处理,只要配置正确授权码流就行。
  • 为什么不用loginPopup:这个方法会自动完成授权码到令牌的交换,适合前端直接用令牌的场景;但要传授权码给后端,就必须手动走授权流程抓码。

内容的提问来源于stack exchange,提问作者WebDev

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 04:07:38