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

Azure Microsoft Graph委托流中无法获取Refresh Token问题排查

无法获取Refresh Token,同时咨询ID Token相关问题(Outlook日历集成项目)

项目背景

我正在开发一个集成Outlook日历的项目,核心需求是自动将作业检查日期添加到用户日历,同时支持用户手动创建日历事件。

已完成的操作

  • 在Azure中创建应用并配置了必要权限(权限配置截图:Azure应用权限配置)
  • 完成测试项目的登录跳转功能,可正常引导用户到Microsoft登录页并完成回调

相关代码

// Define routes
router.get('/login', getAuthCodeUrl);
router.get('/callback', handleCallback);

// In controller
const { ConfidentialClientApplication } = require('@azure/msal-node');

// TEST APP
const clientId = '945bf51b-xxxx-c5a83898b4b8';
const clientSecret = '9mV8Q~xxxx.zf9GqLGt95UUJ_bGdcp';

const msalConfig = {
  auth: {
    clientId: clientId,
    authority: `https://login.microsoftonline.com/common`,
    clientSecret: clientSecret,
  },
};

const redirectUri = 'http://localhost:3000/api/callback';

const scopes = [
  'User.Read',
  'Calendars.ReadWrite',
  'offline_access',
  'openid',
  'profile',
];

const cca = new ConfidentialClientApplication(msalConfig);

const getAuthCodeUrl = async (req, res) => {
  const authCodeUrlParameters = {
    scopes,
    redirectUri,
  };

  const authUrl = await cca.getAuthCodeUrl(authCodeUrlParameters);
  console.log('authUrl: ', authUrl);
  res.redirect(authUrl);
};

const handleCallback = async (req, res) => {  
  console.log('req.query: ', req.query);

  const tokenRequest = {
    scopes,
    code: req.query.code,
    redirectUri,
  };
  console.log('tokenRequest: ', tokenRequest);

  try {
    const authResult = await cca.acquireTokenByCode(tokenRequest);
    console.log('authResult: ', authResult);

    // Handle token result, store tokens, etc.
    res.send('Authentication successful. You can close this window.');
  } catch (error) {
    console.error('Error obtaining access token:', error);
    res.status(500).send('Error obtaining access token');
  }
};

问题现象

访问http://localhost:3000/api/login可正常跳转至Microsoft登录页,登录后进入handleCallback回调,但返回的authResult中缺少Refresh Token,返回内容如下:

{
  authority: 'https://login.microsoftonline.com/common/',
  uniqueId: '00000000-xxxx-ddd3b41006de',
  tenantId: '9188040d-xxxx-36a304b66dad',
  scopes: [ 'User.Read', 'Calendars.ReadWrite', 'openid', 'profile' ],
  account: {
    homeAccountId: '00000000-0000-xxxx.9188040d-6c67-4c5b-b112-36a304b66dad',
    environment: 'login.windows.net',
    tenantId: '9188040d-xxxx-36a304b66dad',
    username: 'nikhilxxxx@gmail.com',
    localAccountId: '00000000-xxxx-ddd3b41006de',
    name: 'Nikhil',
    nativeAccountId: undefined,
    authorityType: 'MSSTS',
    tenantProfiles: Map(1) { '9188040d-xxxx-36a304b66dad' => [Object] },
    idTokenClaims: {
      ver: '2.0',
      iss: 'https://login.microsoftonline.com/9188040d-xxxx-36a304b66dad/v2.0',
      sub: 'AAAAAAAAAAAAXXXXoWCiSKHIxQiLR5lA',
      aud: '945bf51b-xxxx-c5a83898b4b8',
      exp: 1710826775,
      iat: 1710740075,
      nbf: 1710740075,
      name: 'Nikhil Mandaniya',
      preferred_username: 'nikhilmandaniya@gmail.com',
      oid: '00000000-xxxx-ddd3b41006de',
      tid: '9188040d-xxxx-36a304b66dad',
      aio: 'Dv2WQYyaZYlVxxxxsgCzJieAfDrhNDIE6Drp'
    },
    idToken: 'eyJ0eXAiOiJKV1QiLCJhxxxxoQ'
  },
  idToken: 'eyJ0eXAiOiJKV1QiLCJhxxxxoQ',
  idTokenClaims: {
    ver: '2.0',
    iss: 'https://login.microsoftonline.com/9188040d-xxxx-36a304b66dad/v2.0',
    sub: 'AAAAAAAAAAAAAAAAAAAAAICmPO0oWCiSKHIxQiLR5lA',
    aud: '945bf51b-xxxx-c5a83898b4b8',
    exp: 1710826775,
    iat: 1710740075,
    nbf: 1710740075,
    name: 'Nikhil Mandaniya',
    preferred_username: 'nikhilmandaniya@gmail.com',
    oid: '00000000-xxxx-ddd3b41006de',
    tid: '9188040d-xxxx-36a304b66dad',
    aio: 'Dv2WQYyaZYlV19mDrMstNPvJY*xxxxDrhNDIE6Drp'
  },
  accessToken: 'EwBwA8l6BAAUTTy6dbu0OLf3Lzl3RxxxxzaNAg==',
  fromCache: false,
  expiresOn: 2024-03-18T06:39:35.000Z,
  extExpiresOn: 2024-03-18T07:39:35.000Z,
  refreshOn: undefined,
  correlationId: '7a3447ce-xxxx-761ea0a35fde',
  requestId: '29ad5633-xxxx-9f42812f1700',
  familyId: '',
  tokenType: 'Bearer',
  state: '',
  cloudGraphHostName: '',
  msGraphHost: '',
  code: undefined,
  fromNativeBroker: false
}

我的疑问

  1. 为什么无法获取Refresh Token?需要怎么调整才能拿到?
  2. ID Token的定义是什么?在我的项目场景中是否需要使用它?
  3. 如何通过Refresh Token获取新的Access Token?

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 23:04:59