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

MS Teams Bot创建用户对话遇未授权错误的问题咨询

问题:Teams Bot创建用户对话时的未授权错误

我正在开发一个Azure Function应用,需要为Entra ID中的每位用户创建对话,但Bot仅安装在群组频道,执行时出现以下错误:

Error creating conversation2: Error: Error creating conversation: Unauthorized, {"message":"Authorization has been denied for this request."}

当前我使用ConfidentialClientApplication(CCA)生成的Graph Token获取用户列表并尝试创建对话,相关实现如下:

当前实现代码

1. Graph Token获取逻辑

const msalConfig = {
  auth: {
    clientId: process.env.MICROSOFT_APP_ID,
    clientSecret: process.env.MICROSOFT_APP_PASSWORD,
    authority: `https://login.microsoftonline.com/${process.env.TENANT_ID}`,
  }
};

const cca = new ConfidentialClientApplication(msalConfig);

export async function getGraphToken(): Promise<string> {
  try {
    const authResult = await cca.acquireTokenByClientCredential({
      scopes: ['https://graph.microsoft.com/.default']
    });
    console.log('token', authResult.accessToken)
    return authResult.accessToken;
  } catch (error) {
    console.error("Error acquiring Graph token:", error);
    throw new Error("Failed to acquire Graph token");
  }
}

2. 定时器触发的主函数

import { app, InvocationContext, Timer } from "@azure/functions";
import { saveConversationReference, getAllUsers, CreateConversationForMSTeamsUser, addUserRefToStorage } from "../extra/conversationHandlers";

export async function createConversationInStorage2(myTimer: Timer, context: InvocationContext): Promise<void> {
    context.log('Timer function processed request.');

    try {
        const users = await getAllUsers();
        context.log(`Fetched ${users.length} users from Azure AD`);
        for (const user of users) {
            if (user && user.id) {
                context.log(`Processing user: ${user.id}`);
                const res = await CreateConversationForMSTeamsUser(user.id, user.displayName, user.userPrincipalName);
                if (res) {
                    await addUserRefToStorage(user.id, res);
                } else {
                    context.log(`Failed to create conversation for user3: ${user.id}`);
                }
            }
        }
    } catch (error) {
        context.log('Error retrieving users from Azure AD:', error);
    }
}

app.timer('createConversationInStorage2', {
    schedule: '0 */1 * * * *',
    handler: createConversationInStorage2
});

3. 对话创建与用户处理核心函数

import storage from './storageBlob';
import { getBotFrameworkToken, getGraphToken } from './msal';

export async function CreateConversationForMSTeamsUser(userId: string, userDisplayName: string, userPrincipalName: string) {
  try {
    const tenantId = process.env.TENANT_ID;
    const serviceUrl = 'https://smba.trafficmanager.net/teams/v3/conversations'
    const token = await getGraphToken();
    
    const conversationParams = {
      members: [
        {
          id: userId,
          displayName: userDisplayName,
          userPrincipalName: userPrincipalName
        },
      ],
      isGroup: false,
      bot: {
        id: 'id here',
        displayName: 'app name here'
      }
    };

    console.log('conversationParams', conversationParams)

    const conversationResponse = await fetch(
      serviceUrl,
      {
        method: "POST",
        headers: {
          Authorization: `Bearer ${token}`,
          "Content-Type": "application/json",
        },
        body: JSON.stringify(conversationParams),
      }
    );

    console.log('conversationResponse', conversationResponse)

    if (!conversationResponse.ok) {
      const errorText = await conversationResponse.text();
      throw new Error(`Error creating conversation: ${conversationResponse.statusText}, ${errorText}`);
    }

    const conversation = await conversationResponse.json();
    console.log('conversation', conversation)
    return conversation;
  } catch (error) {
    console.error('Error creating conversation2:', error);
    return null;
  }
}

export async function saveConversationReference(userId: string, conversationId: string) {
  const reference = {
    user: { id: userId },
    conversation: { id: conversationId }
  };
  try {
    const res = await storage.add(userId, reference, { overwrite: true });
    console.log(`Conversation reference saved for user ${userId}:`, res);
  } catch (error) {
    console.error(`Error saving conversation reference for user ${userId}:`, error);
  }
}

export async function getAllUsers(): Promise<any[]> {
  const token = await getGraphToken();
  const usersResponse = await fetch("https://graph.microsoft.com/v1.0/users", {
    headers: {
      Authorization: `Bearer ${token}`
    },
  });

  if (!usersResponse.ok) {
    throw new Error(`Error fetching users: ${usersResponse.statusText}`);
  }

  const usersJson = await usersResponse.json();

  if (!usersJson.value || !Array.isArray(usersJson.value)) {
    throw new TypeError('Expected an array of users in the response');
  }

  return usersJson.value;
}

export async function addUserRefToStorage(userId: string, conversationRef: any) {
  try {
    if (!conversationRef) {
      throw new Error('Invalid conversation reference');
    }
    const res = await storage.add(userId, conversationRef, { overwrite: true });
    console.log(`User ID saved for user ${userId}:`, res);
  } catch (error) {
    console.error(`Error saving user conversation reference for ${userId}:`, error);
  }
}

4. Bot Framework Token尝试代码

我猜测可能需要使用Bot Framework Token而非Graph Token,相关获取代码如下:

try {
  const authResult = await cca.acquireTokenByClientCredential({
    scopes: ['https://api.botframework.com/.default']
    // scopes: ['https://smba.trafficmanager.net/.default']
  });
  console.log('authResult', authResult.accessToken);
  return authResult.accessToken;
} catch (error) {
  console.error("Error acquiring Bot Framework token:", error);
  throw new Error("Failed to acquire Bot Framework token");
}

疑问与需求

  • 若使用Bot Framework Token端点,如何配置创建聊天及读写权限?(已为Graph Token配置过相关权限)
  • 如何解决未授权错误,实现为每位用户创建对话?

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 01:24:57