This article illustrates a sample for finding the documents available on a team, with keyword search from channel conversations. This is achieved with the help of outgoing webhook service, where documents from Team are being pulled with the help of Microsoft Graph API.
#Azure #GraphAPI #MicrosoftTeams #Office365
The following screenshot shows the list of documents retrieved sending the keyword via the channel conversation.
In my previous article, we have seen how to retrieve Office365 People data on MS Team Channels via Outgoing Webhook and Azure App Service. The same concept and services are used here, with little tweeks on the code used on my previous article.
Please follow my previous article for configuring the following services.
The webhook service hosted on azure web app does the following actions.
Please find the snippet Node JS code for processing and sending the data from/to the teams channel.
#Azure #GraphAPI #MicrosoftTeams #Office365
The following screenshot shows the list of documents retrieved sending the keyword via the channel conversation.
![]() |
Finding documents from channel using outgoing webhooks |
In my previous article, we have seen how to retrieve Office365 People data on MS Team Channels via Outgoing Webhook and Azure App Service. The same concept and services are used here, with little tweeks on the code used on my previous article.
- Invoke the webhook service from Teams channel, with search keyword.
- Keyword is passed to webhook service, where the service is hosted on azure.
- The service receives the text, manipulates, and uses graph API to find the documents on Teams.
- Once documents response received from graph API, pass and post it on Teams channel with MessageCard (JSON format).
Configuring Services
Please follow my previous article for configuring the following services.
- Creating an outgoing webhook feature on Microsoft Teams.
- Creating an Azure AD app for MS Graph authentications. - Additionally here, the permissions for reading the group data has to be enabled. So Group.Read.All scope under MS graph is added and granted necessary permission.
![]() |
Permissions granted on Azure AD for getting graph API data on Azure web app |
- And finally, create an azure web app with NodeJS, as explained in my previous article. Then modify the azure web app code as explained below to serve the requests for queries generated from Teams channel conversations.
Configuring Webhook service on Azure web app
The webhook service hosted on azure web app does the following actions.
- Receives the request from the channel conversations.
- Extracts only keywords from the conversation text.
- Generates authentication/bearer token using the client credentials, for searching files on the group.
- The GET request has been made with graph API to find files.
Please find the snippet Node JS code for processing and sending the data from/to the teams channel.
This file contains 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
// | |
// Copyright (c) Microsoft. All rights reserved. | |
// Licensed under the MIT license. | |
// | |
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 = "devlab1.onmicrosoft.com"; | |
const CLIENT_ID = "<CLIENT ID FROM AZURE AD APP>"; | |
const CLIENT_SECRET = "<CLIENT SECRET FROM AZURE AD 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 docsStr = ""; | |
response.writeHead(200); | |
if (msgHash === auth) { | |
var receivedMsg = JSON.parse(payload); | |
getToken().then(token => { | |
console.log('Token OK. Next: retrieving files'); | |
GetFiles(token, receivedMsg.text).then(result => { | |
var documents = result; | |
documents.forEach(element => { | |
docsStr += "<p><a href=\"" + element.webUrl + "\">" + element["name"] + "</a>, created by " + element.createdBy.user.displayName + " on " + (new Date(element.createdDateTime)).toGMTString() + "</p>"; | |
}); | |
var responseMsg = { | |
"type": "MessageCard", | |
"@context": "http://schema.org/extensions", | |
"text": usersStr | |
}; | |
response.write(JSON.stringify(responseMsg)); | |
response.end(); | |
}).catch((i, j) => { | |
console.log('An error occurred' + JSON.stringify(i) + '..' + j); | |
});; | |
}); | |
} else { | |
responseMsg = '{ "type": "message", "text": "Error" }'; | |
} | |
} | |
catch (err) { | |
response.writeHead(400); | |
return response.end("Error: " + err + "\n" + err.stack); | |
} | |
}); | |
}).listen(PORT); | |
function GetFiles(token, receivedMsg) { | |
console.log(receivedMsg); | |
receivedMsg = receivedMsg.substr("<at>searchByKeyword</at>".length).trim(); | |
return new Promise((resolve, reject) => { | |
const options = { | |
method: 'GET', | |
url: "https://graph.microsoft.com/v1.0/groups/d658f886-29b3-4c62-aa72-fbe1bf77a070/drive/root/search(q='" + receivedMsg + "')", | |
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); |