Handle Teams Channel Creation with Graph Notifications using Azure Functions

5 minute read

Handle Teams Channel Creation with Graph Notifications using Azure Functions


As a business scenario, we some times needs to hook up to a event when a new Teams channel is happened (for e.g. channel created, deleted, or updated). Graph notifications helps to respond instantly for these scenarios.

In this article, we are going explore on handling the Graph change notifications when Teams channel event has occurred.

Pull vs Push mechanism

There are two scenarios while approaching this business scenario, i.e., pull and push. Each has its own pros and cons as follows:

Pull from Audit logs

All of the user and admin activities in M365 (including Teams channel) is recorded in Audit logs. One can pull the information from Audit logs as needed by running a timer job. While you can decide your own schedule to pull the audit logs, this does not offer a real-time event handling. Also, some times retrieving audit logs (search-unifiedauditlog) may timeout.

Push mechanism with Graph notifications

Graph notifications allows you to respond to the event as it occurs. Although this sounds straight forward, you can subscribe to limited Graph resources listed here. Also, you need to take care of updating the subscription for their renewal.

In this article, we will explore the Graph notifications option.

  1. Azure Logic Apps gets an access token for Microsoft Graph by using Azure AD.
  2. Azure Logic Apps creates a Microsoft Graph subscription and updates it every hour to track changes.
  3. When a Microsoft Graph change notification is processed, the message is handled by Azure Logic Apps.

Azure AD App Registration

As per the documentation, /teams/getAllChannels resource only supports application permission.

Supported resource Delegated (work or school account) Delegated (personal Microsoft account) Application
channel (/teams/getAllChannels – all channels in an organization) Not supported Not supported Channel.ReadBasic.All, ChannelSettings.Read.Al

We will start by registering an app in Azure AD with application permission of Channel.ReadBasic.All. Note down the Application (client) ID, Directory (tenant) ID, and client secret.

Create Function App

Create a function app to handle the Graph notifications.

Create a function

Create a function as HTTP trigger.

Create a Subscription

We will now create a subscription, i.e., a listener application to receive change notifications when the requested type of changes occurs to the specified resource in Microsoft Graph (i.e. Teams channel created).

We will make use of Postman to create the subscription.

Step1: Get Access token

Use the below code to get the access token

POST //oauth2/v2.0/token HTTP/1.1 
Host: login.microsoftonline.com
Content-Type: application/x-www-form-urlencoded


From the response, note down the access_token.

Step 2: Register the subscription

Set Authorization:

  1. Under Authorization, select the type as Bearer Token.
  2. Paste the access_token from previous step as the Token.

Create subscription

Make below POST request to create the subscription.

You will most likely receive an error: Subscription validation request failed. Response must exactly match validationToken query parameter.

Update Function App

The notificationUrl (i.e., Azure function - we will create in next step) must be capable of responding to the validation request as mentioned here.

Update the function app as follows:

# Input bindings are passed in via param block.
param($Request, $TriggerMetadata)

# Response for Subscription Notification Validation. Respond back with validationToken. 
if ($Request.Query.validationToken) {
    Write-Host "RESPONSE: Sending status code 'OK' and validationToken to Subscription Notification Validation Request" 
    Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{
            StatusCode = [HttpStatusCode]::OK
            Body       = $Request.Query.validationToken

Use the Postman request again to create a subscription. It should be successful now.

PowerShell approach

If you prefer the PowerShell way, then you may use the below script (instead of Postman query).

Regsiter the Graph notification for Teams channel created.

Graph notification registration details.

param (
    [parameter(Mandatory = $true)]$ClientID,
    [parameter(Mandatory = $true)]$ClientSecret,
    [parameter(Mandatory = $true)]$TenantID,
    [parameter(Mandatory = $true)]$NotificationURL

$expiryInHours = 1

$clientStateValue = New-Guid

$notificationExpiry = (Get-Date).addHours($expiryInHours).ToUniversalTime()
$utcExpiry = Get-Date $notificationExpiry -Format yyyy-MM-ddThh:mm:ss.0000000Z

# Get Access Token
$accessToken = (Invoke-RestMethod -uri "https://login.microsoftonline.com/$($TenantID)/oauth2/v2.0/token" `
-Method Post `
-Headers @{"Content-Type" = "application/x-www-form-urlencoded" } `
-Body "grant_type=client_credentials&client_id=$($ClientID)&scope=https://graph.microsoft.com/.default&client_secret=$($ClientSecret)").access_token

# Azure AD Users change notification subscription configuration
$createSubscriptionBody = @{
    changeType = "created"
    notificationUrl = $NotificationURL
    resource = "/teams/getAllChannels"
    clientState = $clientStateValue.Guid
    expirationDateTime = "$($utcExpiry)"
    latestSupportedTlsVersion = "v1_2"

# Create Notification Subscription
$newTeamsChannelNotificationSubscription = Invoke-RestMethod -Method Post `
    -Uri "https://graph.microsoft.com/v1.0/subscriptions" `
    -Body ($createSubscriptionBody | ConvertTo-Json) `
    -Headers @{Authorization = "Bearer $($accessToken)"; "content-type" = "application/json" }


Update Azure Function Application settings

Note down the Id and clientState and update them to the Azure Function Application settings as follows:

Azure Function Application Setting Value

We will use these values while subscription renewal and validating the client state.

Renew Subscription

Maximum length of subscription for Teams channel resource type is 60 minutes (1 hour) as mentioned here.

Let us create an Azure function as follows to trigger every hour.

Use below code to renew the subscription.

$ClientID = ""
$ClientSecret = ""
$TenantID = ""

# Get Access Token
$accessToken = (Invoke-RestMethod -uri "https://login.microsoftonline.com/$($TenantID)/oauth2/v2.0/token" `
        -Method Post `
        -Headers @{"Content-Type" = "application/x-www-form-urlencoded" } `
        -Body "grant_type=client_credentials&client_id=$($ClientID)&scope=https://graph.microsoft.com/.default&client_secret=$($ClientSecret)").access_token

# Get Subscription
$notificationSubscription = $null

try {
	$notificationSubscription = Invoke-RestMethod -method GET `
		-Uri "https://graph.microsoft.com/v1.0/subscriptions/$($env:GRAPH_NOTIFICATION_CHANNEL_CREATED_SUBSCRIPTION_ID)" `
		-Headers @{Authorization = "Bearer $($accessToken)"; "content-type" = "application/json"}
catch {	

if ($notificationSubscription) {        
    # Update Subscription 
    $expiryHours = 1
    $notificationExpiry = (get-date).addHours($expiryHours).ToUniversalTime() 
    $utcExpiry = Get-Date $notificationExpiry -Format yyyy-MM-ddTHH:mm:ss.0000000Z

    $updateSubscriptionBody = @{
        expirationDateTime = $utcExpiry

    $extendNotificationSubscription = Invoke-RestMethod -method PATCH `
        -Uri "https://graph.microsoft.com/v1.0/subscriptions/$($env:GRAPH_NOTIFICATION_CHANNEL_CREATED_SUBSCRIPTION_ID)" `
        -body ($updateSubscriptionBody | convertTo-json) `
        -Headers @{Authorization = "Bearer $($accessToken)"; "content-type" = "application/json"}

    Write-Host "New Subscription Expiry: $($extendNotificationSubscription.expirationDateTime)"
    Write-Host "Subscription ClientState: $($extendNotificationSubscription.clientState)"
else {
    Write-Host "Notification not found"

Test the scenario

Create a new channel in any Teams team in the tenant. Watch the output from the http trigger. You should see the TeamID and ChannelID of the newly created channel.

The Graph notification subscription will be renewed by Azure function with timer trigger.


In this article, we explored handling the Graph change notifications when Teams channel event (e.g., created) has occurred using Azure functions.

Code Download

The code developed during this article can be found here.


Leave a comment