Overview
There are multiple business scenarios when in an application you would need to display up to date presence information of a user from Microsoft Teams.
Microsoft had announced
getPresence endpoint to get the user's presence, including their availability and user activity. However, this is a pull mechanism, your application had to make continous polling "get" call to know the current status and if the status is changed in the interim there was no way to know the latest status.
To address this issue, Microsoft has announced a presence subscription API, this API can be used to subscribe other users presence in Microsoft Teams.
Once you create a subscription for the presence for a user and register a HTTPS endpoint to receive a notification, Microsoft Graph will tell you when there are changes. Typically this subscription is good for up to 60 minutes but you can renew them using the
"update subscription" endpoint.
In this article, we will see the step by step configuration to get the users presence status from Microsoft Teams automatically.
Prerequisites
- App registered in Azure active directory(AAD) with Presence.Read and Presence.Read all delegated permissions.
- Install ngrokTool (For Development)
- HTTPS endpoint up and running (For PROD)
Create a web API to receive notifications :
Microsoft Graph will send notifications to a registered HTTPS endpoint. In this case, we will create a ASP.NET Core web API, to receive the notifications.
ngrok is a free tool for sharing projects online that are created in localhost. During development, you can use the
ngrok tool to tunnel the requests via the internet.
1. Open the command prompt and navigate to the directory where you would like to create the project
2. Execute below commands to create ASP.net core Web API
- dotnet new webapi -o PresenceReceiverAPI
3. Once the project is created, navigate to the project directory and execute below commands in the command prompt:
Pl note we are using Microsoft.Graph.Beta instead of Microsoft.Graph so that we can call the beta endpoint of Microsoft Graph API.
- cd PresenceReceiverAPI
- dotnet add package Microsoft.Identity.Client
- dotnet add package Microsoft.Graph.Beta --version 0.20.0-preview
- dotnet run
4.Once you excute above commands application will start and display following in the console:
- info: Microsoft.Hosting.Lifetime[0]
- Now listening on: https:
- info: Microsoft.Hosting.Lifetime[0]
- Now listening on: http:
- info: Microsoft.Hosting.Lifetime[0]
- Application started. Press Ctrl+C to shut down.
- info: Microsoft.Hosting.Lifetime[0]
- Hosting environment: Development
- info: Microsoft.Hosting.Lifetime[0]
- Content root path: [your file path]\PresenceReceiverAPI
5. Press Ctrl+C to stop the application and open your favorite IDE (I like Visual Studio Code..
) to add controllers that receive the notifications.
6. Add below function in the controller class to receive the notification.
- [HttpGet]
- public async Task<ActionResult<string>> Get()
- {
- var graphServiceClient = GetGraphClient();
- var sub = new Microsoft.Graph.Subscription();
- sub.ChangeType = "updated";
- sub.NotificationUrl = config.Ngrok + "/api/notifications";
- sub.Resource = "/users";
- sub.ExpirationDateTime = DateTime.UtcNow.AddMinutes(5);
- sub.ClientState = "SecretClientState";
- var newSubscription = await graphServiceClient
- .Subscriptions
- .Request()
- .AddAsync(sub);
-
- Subscriptions[newSubscription.Id] = newSubscription;
-
- if (subscriptionTimer == null)
- {
- subscriptionTimer = new Timer(CheckSubscriptions, null, 5000, 15000);
- }
-
- return $"Subscribed. Id: {newSubscription.Id}, Expiration: {newSubscription.ExpirationDateTime}";
- }
7. Add below function in the controller class, to verify the validationToken and process the received notification.
- public async Task<ActionResult<string>> Post([FromQuery]string validationToken = null)
- {
-
- if (!string.IsNullOrEmpty(validationToken))
- {
- Console.WriteLine($"Received Token: '{validationToken}'");
- return Ok(validationToken);
- }
-
-
- using (StreamReader reader = new StreamReader(Request.Body))
- {
- string content = await reader.ReadToEndAsync();
-
- Console.WriteLine(content);
-
- var notifications = JsonConvert.DeserializeObject<Notifications>(content);
-
- foreach (var notification in notifications.Items)
- {
- Console.WriteLine($"Received notification: '{notification.Resource}', {notification.ResourceData?.Id}");
- }
- }
-
- await CheckForUpdates();
-
- return Ok();
- }
8. Once you add the code to fetch the access token, "controller" code should be as below:
Create Subscription
1) Create a change notification subscription by submitting an HTTP POST request to the subscriptions endpoint:
Let's look at the parameters that are required :
- changeType - when should the notification trigge. Presence subscription API only support "Updated" parameter.
- notificationUrl - registered HTTPS Endpoint which is up and running. If the endpoint is down, subscription is not created.
- resource - Presence parameter. There are two options to get the presence status : For single-user presence - /communications/presences/{id} For multiple user presence /communications/presences?$filter=id in ({id},{id}...)
- expirationDateTime - subscription expiration time no more than 60 minutes from the time subscription is created.
Typical Post request will appear as below :
- {
- "changeType": "Updated",
- "clientState": "SecretClientState",
- "notificationUrl": "https://f44426ca147b.ngrok.io/api/notifications",
- "resource": "/communications/presences/9974a8dc-d808-421e-8f31-76fbf74f7f1f",
- "expirationDateTime": "2020-08-08T04:30:28.2257768+00:00"
- }
Test the application:
1. Within Visual Studio Code, select Run > Start debugging to run the application.
2. Navigate to the following url: http://<URL created in ngrok>/api/notifications. This will register a new subscription.
3. Now change the status of the user for which subscription is created in Microsoft teams
4. As soon as you change the status, a notification will be triggered and visible in your console.
Below is a typical notification response your HTTPS endpoint will receive, once the status of a user is changed.
Two key properties are returned by API :
- availability, or base presence information e.g: Available, Away, Busy
- activity, or information that’s supplemental to the availability e.g: InAMeeting, InACall
- {
- "value": [
- {
- "subscriptionId": "1221b5ed-ec3f-4036-ac38-042838d55a6f",
- "clientState": "SecretClientState",
- "changeType": "updated",
- "resource": "communications/presences({id})",
- "subscriptionExpirationDateTime": "2020-08-07T21:39:48.2162893+00:00",
- "resourceData": {
- "@odata.type": "#Microsoft.Graph.presence",
- "@odata.id": "communications/presences({id})",
- "id": null,
- "activity": "Busy",
- "availability": "Busy"
- },
- "tenantId": "eafd6ad4-0e37-4c74-b8b4-93a6118d9e75"
- }
- ]
- }
Note :
- Presence subscription API is currently in public preview in Microsoft Graph beta.
- It only supports Delegated user permissions, which means deamon application cannot call this API (as of now).
- Microsoft.Graph NuGet package points to the Microsoft Graph v1.0 version, so you cannot create a subscription using it.