How to connect to Microsoft Graph as an Application in Dialogue Studio
Use this example to search for a Microsoft Graph user with application authentication in Dialogue Studio. Run the flow manually with an Inject node and view the results in the Debug sidebar. This is a test flow, not an Interactive Voice Response, or IVR, is a telephone application to take orders via telephone keypad or voice through a computer. By choosing menu options the caller receives information, without the intervention of a human operator, or will be forwarded to the appropriate Agent. callflow.
Prerequisites
-
Register your app with Formerly known as Azure Active Directory (or Azure AD, or AAD):
Register an application with the Microsoft identity platform - Microsoft Graph
-
Make sure your app has the right API permissions. In this scenario we will be listing users:
Preview
Configure
-
Login to your Dialogue Studio environment
-
Open or create a tab for the diagnostic example.
-
From the menu in the top right, select “Import” and add the following JSON.
JSON[{"id":"6825f548285dd24c","type":"inject","z":"44090047cd950f03","name":"","props":[{"p":"q","v":"Adele","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","x":410,"y":400,"wires":[["cd7612c123f42128"]]},{"id":"cd7612c123f42128","type":"change","z":"44090047cd950f03","name":"Configure Graph configurations","rules":[{"t":"set","p":"client_id","pt":"msg","to":"","tot":"str"},{"t":"set","p":"client_secret","pt":"msg","to":"","tot":"str"},{"t":"set","p":"tenant_id","pt":"msg","to":"","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":610,"y":400,"wires":[["a379927a12a1568c"]]},{"id":"87332f9714da225a","type":"group","z":"44090047cd950f03","name":"Graph Access Token","style":{"label":true},"nodes":["a379927a12a1568c","8514732e52a1c24b","c6d135675889f683","3f60ca50f4703096","9b5d343408d176ce","38b7252002a9a007","09e7933503195b2c"],"x":774,"y":359,"w":952,"h":202},{"id":"a379927a12a1568c","type":"function","z":"44090047cd950f03","g":"87332f9714da225a","name":"Check Token Validity","func":"const currentTime = Math.floor(Date.now() / 1000);\nconst graph = flow.get('graph') || {};\nconst tokenExpiry = graph.tokenExpiry || 0;\nif (currentTime < tokenExpiry) {\n msg.token = graph.accessToken;\n return [msg, null];\n} else {\n return [null, msg];\n}","outputs":2,"timeout":"","noerr":0,"initialize":"","finalize":"","libs":[],"x":920,"y":400,"wires":[["8514732e52a1c24b"],["c6d135675889f683"]]},{"id":"8514732e52a1c24b","type":"function","z":"44090047cd950f03","g":"87332f9714da225a","name":"Use Existing Token","func":"msg.headers = {\n 'Authorization': 'Bearer ' + msg.token,\n 'Content-Type': 'application/json'\n};\nreturn msg;","outputs":1,"timeout":"","noerr":0,"initialize":"","finalize":"","libs":[],"x":1610,"y":400,"wires":[["31c3333f7f7ed396"]]},{"id":"c6d135675889f683","type":"function","z":"44090047cd950f03","g":"87332f9714da225a","name":"Prepare Token Request","func":"msg.credentials = {\n client_id: msg.client_id,\n scope: \"https://graph.microsoft.com/.default\",\n client_secret: msg.client_secret,\n};\nmsg.headers = {\n \"Content-Type\": \"application/x-www-form-urlencoded\",\n \"Host\": \"login.microsoftonline.com\"\n};\nmsg.payload = \"client_id=\" + msg.credentials.client_id + \n \"&scope=\" + msg.credentials.scope + \n \"&client_secret=\" + msg.credentials.client_secret + \n \"&grant_type=client_credentials\";\nmsg.url = 'https://login.microsoftonline.com/' + msg.tenant_id + '/oauth2/v2.0/token';\nreturn msg;\n","outputs":1,"timeout":"","noerr":0,"initialize":"","finalize":"","libs":[],"x":910,"y":480,"wires":[["3f60ca50f4703096"]]},{"id":"3f60ca50f4703096","type":"http request","z":"44090047cd950f03","g":"87332f9714da225a","name":"Get Token","method":"POST","ret":"obj","paytoqs":"body","url":"","tls":"","persist":false,"proxy":"","authType":"","x":1110,"y":480,"wires":[["38b7252002a9a007"]]},{"id":"9b5d343408d176ce","type":"function","z":"44090047cd950f03","g":"87332f9714da225a","name":"Store Token and use New Token","func":"const token = msg.payload.access_token\nconst graph = {\n accessToken: token,\n tokenExpiry: parseInt(msg.payload.expires_on)\n};\nflow.set('graph', graph);\n\nmsg.headers = {\n 'Authorization': 'Bearer ' + token,\n 'Content-Type': 'application/json'\n};\n\nreturn msg;","outputs":1,"timeout":"","noerr":0,"initialize":"","finalize":"","libs":[],"x":1570,"y":480,"wires":[["31c3333f7f7ed396"]]},{"id":"38b7252002a9a007","type":"switch","z":"44090047cd950f03","g":"87332f9714da225a","name":"Check statusCode","property":"msg.statusCode","propertyType":"msg","rules":[{"t":"eq","v":"200","vt":"num"},{"t":"else"}],"checkall":"true","repair":false,"outputs":2,"x":1310,"y":480,"wires":[["9b5d343408d176ce"],["09e7933503195b2c"]]},{"id":"09e7933503195b2c","type":"debug","z":"44090047cd950f03","g":"87332f9714da225a","name":"Failed to get access token","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":1550,"y":520,"wires":[]},{"id":"830e5567b90d92d9","type":"group","z":"44090047cd950f03","name":"Graph user search","style":{"label":true},"nodes":["31c3333f7f7ed396","0a9f69ac8a0da370"],"x":1754,"y":439,"w":412,"h":82},{"id":"31c3333f7f7ed396","type":"function","z":"44090047cd950f03","g":"830e5567b90d92d9","name":"Prepare Contact Request","func":"let q = msg.q;\n\nmsg.url = `https://graph.microsoft.com/v1.0/users/?$filter=startswith(givenName, '${q}') OR startswith(surname, '${q}')`\n\nreturn msg;\n","outputs":1,"timeout":"","noerr":0,"initialize":"","finalize":"","libs":[],"x":1890,"y":480,"wires":[["0a9f69ac8a0da370"]]},{"id":"0a9f69ac8a0da370","type":"http request","z":"44090047cd950f03","g":"830e5567b90d92d9","name":"Get User","method":"GET","ret":"obj","paytoqs":"ignore","url":"","tls":"","persist":false,"proxy":"","insecureHTTPParser":false,"authType":"","senderr":false,"headers":[],"x":2080,"y":480,"wires":[["edda6328adde524b"]]},{"id":"7accd12afb3b8f8b","type":"group","z":"44090047cd950f03","name":"Validate Output","style":{"label":true},"nodes":["64cb2f49f8223bb7","ed6baeaa014fe008","cded1fd225699fc1","edda6328adde524b","b69564284d807e37","31f0ce7110441147","9f51a794e7cbf61d"],"x":2174,"y":319,"w":972,"h":242},{"id":"64cb2f49f8223bb7","type":"switch","z":"44090047cd950f03","g":"7accd12afb3b8f8b","name":"Check if any results","property":"msg.payload.value[0]","propertyType":"msg","rules":[{"t":"nnull"},{"t":"else"}],"checkall":"true","repair":false,"outputs":2,"x":2510,"y":420,"wires":[["31f0ce7110441147"],["ed6baeaa014fe008"]]},{"id":"ed6baeaa014fe008","type":"debug","z":"44090047cd950f03","g":"7accd12afb3b8f8b","name":"no results","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":2940,"y":440,"wires":[]},{"id":"cded1fd225699fc1","type":"debug","z":"44090047cd950f03","g":"7accd12afb3b8f8b","name":"Returned single contact","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload.value[0]","targetType":"msg","statusVal":"","statusType":"auto","x":2990,"y":400,"wires":[]},{"id":"edda6328adde524b","type":"switch","z":"44090047cd950f03","g":"7accd12afb3b8f8b","name":"Check statusCode","property":"statusCode","propertyType":"msg","rules":[{"t":"eq","v":"200","vt":"num"},{"t":"else"}],"checkall":"true","repair":false,"outputs":2,"x":2290,"y":480,"wires":[["64cb2f49f8223bb7"],["b69564284d807e37"]]},{"id":"b69564284d807e37","type":"debug","z":"44090047cd950f03","g":"7accd12afb3b8f8b","name":"Failed to retreive information","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":2540,"y":520,"wires":[]},{"id":"31f0ce7110441147","type":"switch","z":"44090047cd950f03","g":"7accd12afb3b8f8b","name":"Check if multiple results","property":"msg.payload.value[1]","propertyType":"msg","rules":[{"t":"nnull"},{"t":"else"}],"checkall":"true","repair":false,"outputs":2,"x":2730,"y":400,"wires":[["9f51a794e7cbf61d"],["cded1fd225699fc1"]]},{"id":"9f51a794e7cbf61d","type":"debug","z":"44090047cd950f03","g":"7accd12afb3b8f8b","name":"Multiple results","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload.value","targetType":"msg","statusVal":"","statusType":"auto","x":2960,"y":360,"wires":[]}] -
Open Change node (labeled Configure Graph configurations) and fill in:
-
client_id = Can be copied from the App Registration > Overview page.
-
client_secret = Can be created and copied from the App Registration > Manage > Certificate & secrets
-
tenant_id =Can be copied from the App Registration > Overview page.
-
-
Open the Inject node and enter name of the user you want to search.
-
The five Debug nodes in the imported example are disabled. Enable only the diagnostic outputs you need, using each Debug node's enable button. Select Deploy to apply the example configuration, then select the blue button beside the Inject node to run the lookup.
-
Open the Debug sidebar to view the enabled outputs. Depending on the response, the flow reaches Failed to get access token, Failed to retreive information, no results, Returned single contact, or Multiple results. Outputs can contain user data or error details. Disable the Debug nodes after testing, and do not share credentials or tokens.
For an example of handling reported flow errors, see How to configure a catch node in Dialogue Studio. Check how your flow handles HTTP timeouts as well.
Explanation
Trigger Flow
Action:
The flow is triggered by an inject node which initiates the process with a predefined query.
What it does:
This node starts the flow by injecting a message with a property q set to the string Adele. This is the initial step to search for a user in Microsoft Graph.
Configure Graph Configurations
Action:
The “Configure Graph configurations” change node sets up the necessary configuration variables for Microsoft Graph.
What it does:
This node assigns values to client_id, client_secret, and tenant_id in the message object. These variables are essential for authenticating and accessing Microsoft Graph services.
Graph Access Token
The request uses the Microsoft v2 token endpoint, but the example reads the token expiry from msg.payload.expires_on. A response containing expires_in without expires_on does not provide the expiry value this flow expects. Do not rely on the example for token caching or renewal until the expiry handling has been corrected and tested.
Action:
These nodes check the stored expiry time, request an access token, and set the authorization header.
What it does:
-
Check Token Validity: Compares the stored expiry time with the current time. The flow uses the stored token if it has not expired, or requests a new token otherwise. This checks the stored expiry time, not whether Microsoft Graph accepts the token.
-
Use Existing Token: Sets the authorization header using the stored token.
-
Prepare Token Request: Sets the URL, headers, and payload for the token request.
-
Get Token: Sends an HTTP POST request to obtain a new access token.
-
Store Token and use New Token: Stores the new token and the parsed
expires_onvalue in flow context, then sets the authorization header with the new token. -
Check statusCode: Checks whether the HTTP response status code is 200 (OK). Other responses are routed to the corresponding Debug node, which displays output only when enabled.
Graph User Search
Action:
This group of nodes prepares and sends a request to search for a user in Microsoft Graph.
What it does:
-
Prepare Contact Request: Constructs the URL for the Microsoft Graph API to search for users based on the query. It formats the query to match the expected format for user names.
-
Get User: Sends an HTTP GET request to the constructed URL to retrieve user information.
Validate Output
Action:
This group of nodes validates the response from the Microsoft Graph API and processes the results.
What it does:
-
Check statusCode: Checks whether the HTTP response status code is 200 (OK). Other responses are routed to the corresponding Debug node, which displays output only when enabled.
-
Check if any results: Checks if the response contains any user data.
-
Check if multiple results: Determines if the response contains multiple users.
-
Debug nodes: When enabled, these nodes display the configured payload or result values in the Debug sidebar. They distinguish no results, a single result, and multiple results. Keep the supplied output properties; do not change them to display the complete message, which also carries authentication data.
