Sending Graph API based notifications to Teams as Adaptive Cards with Logic Apps, Managed Identities and the Incoming Webhook connector
There are many cases when you might want to build some automation to first check something periodically in Graph API and then report directly to Teams if certain conditions are met. For example, some organizations might want to get automatic alerts in Teams when the amount of certain types of free licenses goes under a specific threshold.
I've seen multiple ways to achieve this but many might involve setting up Power Automate service accounts, which create new licensing, security, and management requirements. Accessing the Graph API on the other hand often involves creating an app registration and giving it application permissions to the required resources, then operating that application using a secret or certificate in a Logic Apps workflow. While this can be handled using Azure Key Vault and secured inputs & outputs in the Logic App, it still introduces new questions concerning securing access to the secrets used for authentication. Also, the life cycle of secrets or certs needs to be managed.
It would be preferable, then, to both query the Graph API and send the messages to Teams without relying on apps, secrets, or licensed service accounts.
Good thing we have a way to tackle this!
Managed identities to the rescue
Logic Apps is able to leverage something called managed identities. Let's see Microsoft's definition of them:
Managed identities provide an identity for applications to use when connecting to resources that support Azure Active Directory (Azure AD) authentication.
There are two kinds of managed identities: user-assigned and system-assigned. Here's a simplified explanation of each from the perspective of Logic Apps, although managed identities can be used with other Azure services as well:
If you rely solely on the Azure portal, managed identities cannot be given permissions to access the Graph API. You can, however, give these permissions using the Azure AD Powershell. This unlocks whole new and interesting usage scenarios.
As usual, let's build an example scenario to illustrate the coolness.
Example case: Automated license reporting
Our goals are the following:
We'll start by creating a new Logic App. Note that the first four thousand actions for consumption plan Logic Apps are now free in every tenant, so if you're not already running any Logic Apps, you can set something like this up without any recurring cost.
With the resource created, we need to enable the system-assigned managed identity. To do this, open the Logic app and navigate to Identity under settings.
On the System assigned tab, we will set the Status to On and grab the principal ID of the managed identity. We need this so we can give the necessary Graph API application permissions to the managed identity.
We want to make sure we have the Service Principal ID, our Tenant ID, and the name of the desired Graph API permission at hand. Then, let's connect to the Azure AD PowerShell.
In my case, I put together and used this script [Pastebin link] to add the required Organization.Read.All permission to the system-assigned managed identity of my Logic App.
After running the script, I checked the enterprise app of the managed identity and verified that the permission was correctly set. ?
Preparing things on the Teams end
As part of the workflow, I want to send messages to Teams from Logic Apps. To do this in a handy way, we'll make use of the Incoming Webhook connector, which can be used to send messages to Teams channels programmatically. Specifically, we're looking to leverage the ability of the connector to support Adaptive Cards, for which at least schema version 1.2 is supported.
I opened Teams, navigated to the desired Teams team, and created a channel for alerts. Then, I accessed the Connectors menu under the triple dot menu next to the channel's name.
In the Connectors menu we can find the Incoming Webhook connector. I chose Add to get started configuring it for the team & channel.
There aren't really many steps to configure an Incoming Webhook - just give it a name, an optional custom icon and grab the provided webhook URL, which we will use later. Also, take diligent care of the webhook URL - you don't want to distribute or even save it in any visible place, since anyone can use it to send messages to the channel without authentication!
领英推荐
The webhook URL will look something like https://tenantName.webhook.office.com/webhookb2/(long identifier string)
Things are now ready on the Teams end. Time to build the Logic App!
Building a Logic App
I took the foundational inspiration for this Logic App from Jan Bakker's blog from 2020. Here's how we will approach this:
We set the workflow to run Monday through Friday at 8AM.
We use the Logic App's system-assigned managed identity - now equipped with the necessary permissions - to poll the subscribedSkus resource in Graph API to get full license data for our tenant. Note how no credentials need to be retrieved or passed as part of the workflow.
We then parse the response from Graph and collect the assigned/active and total license amounts for the desired license type. We could also parse the data for all licenses if needed.
I also designated the minimum number of free licenses - say, 20 - that will act as a threshold for our automation. (The blog I linked uses a percentage-based approach to threshold-setting, which might be useful when dealing with large and/or shifting license pools, in which an arbitrary number might not be the best approach.)
We can use the Condition action to check if the number of free licenses is below the set threshold.
Finally, if the condition is triggered, we utilize the HTTP action to post our custom adaptive card with dynamic information from the workflow through the webhook URI to Teams.
To easily design your Adaptive Card and get ready-made valid JSON for a workflow, I recommend using Microsoft's excellent Adaptive Card designer. Both it and the schema explorer come in very handy when building anything from enterprise grade automation to easy Power Automate snap solutions for teamwork purposes.
In this solution I used a bunch of dynamic content from Graph API to enhance the adaptive card's content and make it a bit more informative. Here is a demonstrative snippet:
I also strongly recommend turning on both Secured Inputs & Secured Outputs for the HTTP POST action. This makes sure it isn't possible to extract the URI of the Teams webhook just by looking at the run history of the workflow. An example of the intended outcome can be seen below.
To provide a final addition to the user experience, I hopped over to Teams and subscribed to new post notifications for the Alerts channel. This is an individual action any user can perform to make sure they get fast visibility to any new alerts pushed to Teams.
Time for a test run! I manually triggered the Logic App and hopped over to Teams. It took only 2.83 seconds for the workflow to run before a promising notification from the Teams app popped up in my Windows activity feed:
A single click and I was transported directly to the alert message in Teams, where I could easily start both acting and communicating to resolve the situation.
I hope you enjoyed this exploration. ?? Are you using Logic Apps for Teams notifications already? If so, please share your use case!
Have a good one!
-Tatu