Here, let us see how office 365 people information can be integrated into Microsoft Teams, with the help of outgoing webhooks on Teams. The use case is to pull the people present at a location, on posting a message to a service from Microsoft Teams.
This could be easily achieved with the help of outgoing webhook feature under teams. The webhook has to interact with a service to get data processed based on data posted.
Why Outgoing Webhook?: The outgoing webhook is used here instead of incoming webhook, since the data needs to be retrieved only when it is required.
No BOT Framework, only Azure App Service: This article helps us to understand creating outgoing webhook services for Microsoft Teams, without creating BOT service/app. Here the intent of service is clear, so we are not leveraging the BOT framework, instead hosting a simple service with Azure web app. From azure web app, the people data is being pulled from Azure AD with the help of Microsoft Graph API.
Create an outgoing webhook for a Microsoft Team
Locate a team under Microsoft Teams, and navigate to manage team. Under App, in the bottom right corner, you will find an outgoing webhook link. From the link, create a webhook.
![]() |
Outgoing Webhook creation on Teams |
NOTE: This will generate a security code for communication, which needs to be copied and pasted on sharedSecret variable on for later use on Azure web app server.js code.
Create an Azure AD app for MS Graph authentications
Azure app service needs to get the people information for a specific city from Azure AD, via Microsoft Graph API.
- Graph API used on Azure App: https://graph.microsoft.com/v1.0/users?$filter=City eq '<cityname>’
For authenticating the above graph API end, the azure AD app needs to be created, where necessary permissions will be provisioned. In this case, the user permission needs to be granted from application type as shown below. The client credentials can be generated and copied to Azure web app service for authentications.
Create an Azure web app
From azure portal, create a web app with Node JS capability. The following server side code shows the web app service (i.e., webhook service), which reacts to the data from teams.
Please note to change the shared secret value and client credentials, from the configurations explained above. Install the necessary modules, and publish the app service.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const crypto = require('crypto'); | |
const sharedSecret = "<Security token generated by Microsoft Teams>"; // e.g. "+ZaRRMC8+mpnfGaGsBOmkIFt98bttL5YQRq3p2tXgcE=" | |
const bufSecret = Buffer(sharedSecret, "base64"); | |
var http = require('http'); | |
var PORT = process.env.port || process.env.PORT || 8080; | |
var adal = require('adal-node'); | |
var request = require('request'); | |
const TENANT = "<your_tenantname>.onmicrosoft.com"; | |
const CLIENT_ID = "<Client ID generated from Azure AD APP>"; | |
const CLIENT_SECRET = "<Client secret generated for above client app>"; | |
const GRAPH_URL = "https://graph.microsoft.com"; | |
function getToken() { | |
return new Promise((resolve, reject) => { | |
const authContext = new adal.AuthenticationContext(`https://login.microsoftonline.com/${TENANT}`); | |
authContext.acquireTokenWithClientCredentials(GRAPH_URL, CLIENT_ID, CLIENT_SECRET, (err, tokenRes) => { | |
if (err) { reject(err); } | |
resolve(tokenRes.accessToken); | |
}); | |
}); | |
} | |
http.createServer(function (request, response) { | |
var payload = ''; | |
// Process the request | |
request.on('data', function (data) { | |
payload += data; | |
}); | |
// Respond to the request | |
request.on('end', function () { | |
try { | |
// Retrieve authorization HMAC information | |
var auth = this.headers['authorization']; | |
// Calculate HMAC on the message we've received using the shared secret | |
var msgBuf = Buffer.from(payload, 'utf8'); | |
var msgHash = "HMAC " + crypto.createHmac('sha256', bufSecret).update(msgBuf).digest("base64"); | |
var responseMsg = ''; | |
var usersList = ""; | |
var usersStr = ""; | |
response.writeHead(200); | |
if (msgHash === auth) { | |
var receivedMsg = JSON.parse(payload); | |
getToken().then(token => { | |
console.log('Token OK. Next: create the group'); | |
GetUsers(token, receivedMsg.text).then(result => { | |
var users = result; | |
users.forEach(element => { | |
usersStr += element["displayName"] + " <" + element["mail"] + ">,"; | |
}); | |
responseMsg1 = '{ "type": "message", "text": "' + usersStr + '" }'; | |
response.write(responseMsg1); | |
response.end(); | |
}).catch((i, j) => { | |
console.log('An error occurred while creating the group' + JSON.stringify(i) + '..' + j); | |
});; | |
}); | |
} else { | |
responseMsg = '{ "type": "message", "text": "Error: message sender cannot be authenticated." }'; | |
} | |
} | |
catch (err) { | |
response.writeHead(400); | |
return response.end("Error: " + err + "\n" + err.stack); | |
} | |
}); | |
}).listen(PORT); | |
function GetUsers(token, CityName) { | |
CityName = CityName.split(' ')[1].trim(); | |
console.log("https://graph.microsoft.com/v1.0/users?$filter=City eq '" + CityName + "'"); | |
return new Promise((resolve, reject) => { | |
const options = { | |
method: 'GET', | |
url: "https://graph.microsoft.com/v1.0/users?$filter=City eq '" + CityName + "'", | |
headers: { | |
'Authorization': 'Bearer ' + token, | |
'content-type': 'application/json' | |
} | |
}; | |
request(options, (error, response, body) => { | |
const result = JSON.parse(body); | |
if (error) { | |
reject(result); | |
} else { | |
resolve(result.value); | |
} | |
}); | |
}); | |
} | |
console.log('Listening on port %s', PORT); | |
//Code template extracted from Microsoft supported site. The code has been customized for the requirement. |
Test Outgoing Webhook on Microsoft Teams
Now, the outgoing webhook can be tested from Teams. Post the webhook name, along with city name on Teams as shown below. The azure app service will be triggered via webhook and the repsonse will be posted to the message thread as shown below.
Advantage of using App Service over BOT framework: There are little complexities involved in building Azure BOT service than Azure App service, where proper data training needs to provided, along with intent creations on LUIS. Also, my requirement was straight forward, where no intent and data training is required.
![]() |
Teams integrated with App service for retrieving people information |
Advantage of using App Service over BOT framework: There are little complexities involved in building Azure BOT service than Azure App service, where proper data training needs to provided, along with intent creations on LUIS. Also, my requirement was straight forward, where no intent and data training is required.