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

从Azure AD获取Refresh Token时遇AADSTS9002313错误求助

解决Azure AD获取Refresh Token时的AADSTS9002313错误

错误详情

data {"error":"invalid_grant","error_description":"AADSTS9002313: 请求无效。请求格式不正确或无效。\r\nTrace ID: 4bcb6e5e-35c1-4c4e-b184-d0ffddcc6301\r\nCorrelation ID: 689f7abd-13ef-41f9-b94a-4b2269bb7c32\r\nTimestamp: 2023-03-03 11:15:39Z","error_codes":[9002313],"timestamp":"2023-03-03 11:15:39Z","trace_id":"4bcb6e5e-35c1-4c4e-b184-d0ffddcc6301","correlation_id":"689f7abd-13ef-41f9-b94a-4b2269bb7c32","error_uri":"https://login.microsoftonline.com/error?code=9002313"}

代码问题及修复方案

1. Token端点未启用

代码中tokenEndpoint被注释,导致请求无有效目标地址。取消注释并选择对应端点:

  • 多租户应用用通用端点:https://login.microsoftonline.com/common/oauth2/v2.0/token
  • 单租户应用用特定租户端点:https://login.microsoftonline.com/{你的租户ID}/oauth2/v2.0/token

2. 异步逻辑顺序错误

res.end(refreshToken)在fetch请求完成前就执行,此时refreshToken未赋值,还会提前终止响应。需把响应逻辑移到fetch的then回调内。

3. 手动截取Code存在风险

直接字符串截取获取code参数,若参数顺序变化或含URL编码字符,会导致参数失效。改用url模块解析Query参数更可靠。

4. 请求参数未做URL编码

client_secret等参数若含特殊字符(如&、=),直接拼接会破坏请求格式,必须用encodeURIComponent对每个参数编码。

5. 额外校验项

  • 确保Azure AD应用注册里的redirect_uri和代码中完全一致(包括大小写、结尾斜杠)
  • Authorization Code是一次性的,重复使用会触发invalid_grant错误,必须用全新的code

修正后的代码

const http = require('http');
const url = require('url');
const hostname = '127.0.0.1';
const port = 3000;

const server = http.createServer((req, res) => {
  res.statusCode = 200;
  res.setHeader('Content-Type', 'text/plain');

  // 解析请求URL中的query参数
  const queryParams = url.parse(req.url, true).query;
  const code = queryParams.code;

  if (!code) {
    res.end('缺少code参数');
    return;
  }

  const tokenEndpoint = 'https://login.microsoftonline.com/common/oauth2/v2.0/token';
  const clientId = '你的客户端ID';
  const redirectUri = 'http://localhost:3000/callback';
  const grantType = 'authorization_code';
  const clientSecret = '你的客户端密钥';

  // 对所有参数进行URL编码,避免格式错误
  const tokenRequestBody = [
    `grant_type=${encodeURIComponent(grantType)}`,
    `code=${encodeURIComponent(code)}`,
    `redirect_uri=${encodeURIComponent(redirectUri)}`,
    `client_id=${encodeURIComponent(clientId)}`,
    `client_secret=${encodeURIComponent(clientSecret)}`
  ].join('&');

  const tokenRequest = {
    method: 'POST',
    headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
    body: tokenRequestBody
  };

  fetch(tokenEndpoint, tokenRequest)
    .then(response => {
      if (!response.ok) {
        throw new Error(`HTTP错误状态: ${response.status}`);
      }
      return response.json();
    })
    .then(data => {
      if (data.error) {
        res.end(`错误: ${data.error_description}`);
        return;
      }
      const refreshToken = data.refresh_token;
      res.end(`Refresh Token获取成功: ${refreshToken}`);
    })
    .catch(error => {
      res.end(`请求失败: ${error.message}`);
    });
});

server.listen(port, hostname, () => {
  console.log(`Server running at http://${hostname}:${port}/`);
});

内容的提问来源于stack exchange,提问作者ab.it.gcp

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.29 22:02:06