Microsoft Graph webhooks or the ability to receive an Azure AD Change Notification has been around for some time. However, as I primarily deal with Azure AD for user and group objects I never previously had the need to utilize them. Using Azure AD delta queries was always enough. Until recently, whereby I needed a solution that could be triggered by changes to Azure AD Guest objects. Azure AD Change Notifications is the answer.
This post details an example solution to get started with Azure AD Change Notifications. It covers;
The diagram below shows an overview of the example detailed in this post.
The example in this post utilizes three Azure PowerShell Functions. I’ve implemented three separate functions so that each performs specific functionality. The three Azure Functions are;
Using the Azure Portal create a new Function App that will host the Azure Functions. VSCode will be used to create and publish the Azure Functions using PowerShell.
For this example, I’m using the consumption plan. With this plan there are not a large number of resources associated with it. And as two of the Functions interoperate with each other the Azure Function Application Settings will need to be updated for PowerShell Concurrency. I posted about this in this topic, and I am using 4 again successfully for the configuration.
After validation completes the Function App can be created.
In your file explorer create the folder where you will locate your Azure Functions locally. In VSCode open that folder and ensure that your Terminal is using PowerShell (formally PowerShell Core, and NOT Windows PowerShell). Ensure you have the latest Azure Functions Core Tools by running the following command.
npm install -g azure-functions-core-tools@3 --unsafe-perm true
The first Azure Function that we will create is the one that receives the Azure AD Change Notifications and sends validation of receipt. Create a New Local Project.
Choose PowerShell as the language
As this function will receive the Azure AD Change Notifications make it an HTTP Trigger Function.
I’ve named my function “ReceiveChangeNotification“
And configured the Authorization level as Function.
With the Azure Function created, expand the Local Project => Functions, select the new Function, expand the function name and select run.ps1.
Press F5 to run the Function App locally.
Call the function app from PowerShell using the following command (assuming that your local instance is also running on Port 7071, and you named your function the same as mine (ReceiveChangeNotification).
Invoke-RestMethod -Method Post -Uri http://localhost:7071/api/ReceiveChangeNotification -body '{"name": "Darren"}' -ContentType "application/json"
If you’ve configured everything correctly you should see the following response from calling the new Azure Function.
For this example, I’m going to send event information as an email. I will use the SendGrid output binding to do this. I’ve previously written about enabling Twilio SendGrid for Azure Functions. This integration will use the same. Twilio SendGrid will be used to send an email notification when an Azure AD Change Notification is received. It will contain the details of the Azure AD User Object that has been updated.
Using the Azure Portal whilst in the Resource Group associated with your Azure Function App, from the Azure Marketplace add Twilio SendGrid to your environment then:
The following shows the configuration of Twilio SendGrid when added from the Azure Marketplace. I’m using the Free 100 Monthly plan for this example.
After Twilio SendGrid is deployed select the Configure account now button to continue the configuration in the Twilio Portal.
Create Single Sender Verification with a From and Reply address for your environment. I’m using the same address for both From and Reply. Once configured, go to the associated Inbox for the email account and verify the address.
Finally, we need an API Key for SendGrid to be able to integrate our Azure Function Apps SendGrid output bindings. I used the CURL example integration to trigger the flow to allow configuration of an API key.
We now need to configure an Azure Function for our SendGrid configuration.
Open the run.ps1 file for the ReceiveChangeNotification Azure PowerShell Function. Replace it with the following script. It contains the logic to reply to a new subscription, reply to change notifications and send a summary email to the configured (in your local.settings.json) email address.
Now it’s time to deploy the Azure Function to Azure. After selecting Deploy and selecting the Function App that you created earlier it will deploy to Azure. After deployment it will display a notification asking whether to also send the local settings configuration. Select Yes.
Azure AD Change Notifications Subscriptions are created under the context of a user. I strongly recommend creating a dedicated Azure AD User in the associated Azure Tenant that will be used to create and maintain the change notifications subscription. After creating the Azure AD User account that will be used for the Azure AD Change Notification Subscriptions login with that account and change the password.
The Resource Types and syntax for change notifications are available here. For this example, I’m creating a notification for changes to user objects in Azure AD. We will need to create an Azure AD Application Registration that contains Microsoft Graph permissions to read Subscriptions (Subscriptions.Read.All) as well as permissions to create Notification Subscriptions. For the /Users objectClass that is User.Read.All.
The permissions required for notification subscriptions by resource type (e.g. Users, Groups) is detailed here.
On your Azure AD Application Registration select API permissions => Add a permission => Microsoft Graph => Delegated permissions => Subscription.Read.All & User.Read.All=> Add permissions.
Then select the Grant admin consent for <your directory name>.
Record the ClientID (ApplicationID) of the Azure AD Application Registration as well as the TenantID of the Azure AD Directory.
We can now use PowerShell to authenticate to Azure AD using the User Account created earlier as well as leveraging the registered AAD application and its permissions. As mentioned at the beginning Azure AD Change Notifications Subscriptions have a lifetime. For the /Users objectClass that is 3 days. We will create a subscription for 1/2 of that lifetime and maintain it with another function that we will create shortly.
To automate the creation of the subscription (and later the updates to extend the lifetime) using delegated permissions we need to use both the AAD User and the AAD Registered App we created above. Update the following script to provide your Azure AD ApplicationID, Client Secret, TenantID, AAD User UPN and Password. On Line 24 also provide the URL to your Azure PowerShell Function.
The Azure AD Change Notification Subscription is now created. Take note of the ClientState and the Id values. The Id will be configured in the notificationSubscriptionID variable and the ClientState will be configured in the clientStateValue variable in our Function App Settings. These are used to validate notification messages and update the notification subscription.
{ "code": "Iy8bpuOOiLwVtW........QoxBntTbXGQ==", "validationToken": "Validation: Testing client application reachability for subscription Request-Id: 9bcab39f-e09d-44fc-9a39-a65934673111" }
To test that our function is working correctly, update an Azure AD User account or create a new one in the Tenant. Within a few minutes you should receive an email (via SendGrid) with the details.
Now that we have shown we can receive notifications for our change notification subscription we need to manage the subscription on-going so that we can continue to receive subscription notifications. To do that we will create a Trigger PowerShell Azure Function. It will renew the notification subscription.
From the VSCode Project create a new Azure Function. This time make it:
Open the run.ps1 file for the new Azure Function and replace the script with the following contents.
Edit the local.settings.json to add entries with your values for the clientState, Notification Subscription ID, AAD App Client ID, AAD App Client Secret, AAD Tenant ID, AAD User Account and Password.
This is storing the credentials and configuration in the Azure Function Application settings. It is highly recommended that you store these in an Azure Key Vault and retrieve them at runtime from their using Managed Identity. This post has the details on how to do that.
Deploy the Azure Function App to publish the changes along with the new NotificationSubscriptionMgmt Azure Function.
In the PowerShell session you used to create the Azure AD Change Notification you can use the following snippet to query the subscription. On the schedule (every 12 hours) you will see it update. Update the snippet for the ID of the change notification subscription you created.
$usersNotificationSubscription = Invoke-RestMethod -method GET -uri "https://graph.microsoft.com/v1.0/subscriptions/yourNotificationSubscriptionID"
-Headers @{Authorization = "Bearer $($delegatedToken)"; "content-type" = "application/json"}
$usersNotificationSubscription.expirationDateTime
$usersNotificationSubscription.clientState
The final Function App. The one that will do something with the change notification. For this example, I’m just going to query Azure AD for the User object that we got the change notification for and get the full user object and their group memberships, then send those details in an email (again via SendGrid).
For a production implementation you would look to use Microsoft Graph Delta Queries to get more granular and efficient with the changes.
Create another Azure Function in your Function App with the configuration;
Right click the new Azure Function and select Add Binding. Add an output binding for SendGrid just as we did earlier for the first Azure PowerShell Function. Deploy the Azure Function again. When complete right click on the new Azure Function and copy the Function URL. Update the run.ps1 script file for the ReceiveChangeNotification Function to include the following section at the bottom. Update the snippet with your new Function URL.
# Call the AD Query Function to retrieve objects and perform required logic.
if ($objNotification.clientState -and $objNotification.resource) {
write-host "FORWARDING: Sending change notification details to AzureADQuery Function"
Invoke-RestMethod -Method Post -Uri "https://yourAzureFunctionApp.azurewebsites.net/api/azureadquery?code=spl3I...yourFunctionCode...g%3D%3D"
-headers @{"Content-Type" = "application/json" } `
-body "clientState=$($objNotification.clientState)&updatedObject=$($objNotification.resource)"
}
Edit the run.ps1 file for the new Azure PowerShell Function and replace the script with the following contents.
It will receive from the object that has changed and the clientState from the ReceiveChangeNotifcation Function and then query Azure AD to get the user object. If the object is a Guest account it will also get the group memberships then send a summary email via SendGrid.
Deploy the Azure Functions again to publish them to Azure.
With our third Azure Function deployed when we update an Azure AD Guest User Object we get two emails. One email when the change notification is received, and the second email containing the results of the Azure AD query.
In the post I’ve shown how to
A few weeks back the Microsoft AI Tour was in Sydney Australia. There was a…
If you're anything like me you always have PowerShell open, and often both PowerShell and…
Decentralised Identity is a technology I'm passionate about and have written many posts and tools…
Over two years ago I authored a PowerShell Module that enabled the automation of 1Password.…
Buried in my PowerShell Snippets Vol 4 post from 2021 is the PowerShell script and…
Short post on how to recovery from "The Windows Subsystem for Linux instance has terminated"…
This website uses cookies.
View Comments