I am creating an azure function app that should create a conversation with every user in Entra Id- I run into an error message: Error creating conversation2: Error: Error creating conversation: Unauthorized, {“message”:”Authorization has been denied for this request.”}.
I use a graph token generated with the CCA – code below
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");
}
}```
i use this to get every user in Entra and then for each user, i try to create and save a conversation
```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
});```
- handlers below
```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/amer/v3/conversations';
const serviceUrl = 'https://smba.trafficmanager.net/teams/v3/conversations'
const token = await getGraphToken();
// console.log('everything', userId, userDisplayName, userPrincipalName, tenantId, serviceUrl)
// console.log('emicrosoft details', 'appid', process.env.MICROSOFT_APP_ID, 'appsecret', process.env.MICROSOFT_APP_PASSWORD, 'tenantid', process.env.TENANT_ID)
const conversationParams = {
members: [
{
id: userId,
displayName: userDisplayName,
userPrincipalName: userPrincipalName
},
],
isGroup: false,
bot: {
id: 'id here',
displayName: 'app name here'
}
};
console.log('conversationParams', conversationParams)
// const conversationParams = {
// activity: 'hi',
// bot: [
// {
// aadObjectId: process.env.MICROSOFT_APP_ID,
// id: 'id here',
// name: 'app name here',
// role: 'bot'
// }
// ],
// channelData: { tenant: { id: tenantId } },
// isGroup: false,
// members: [
// {
// aadObjectId: userId,
// id: `29:${userId}`,
// name: userDisplayName,
// role: 'user',
// userPrincipalName: userPrincipalName
// }
// ],
// tenantId: tenantId,
// topicName: 'General'
// }
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);
}
}
- i also had a theory there might be some other type of token that im supposed to use- apparently i can pass it the botframwork scope and get a token. if this is the endpoint im supposed to use, how do i give it permission to create chats and readwrite permission? (this is already done for the 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");
}
}