Episode #133 – Back-end API of a Microsoft Teams Tabs with Single Sign-On

Here you can find the transcript of Episode #133 of PiaSys TechBites.

Welcome back to PiaSys Tech Bites. Today I’m really excited because I’m going to talk with you about a topic that I really like. Last week we saw that we can easily create, using the Yo Teams generator, a Teams tab or a Teams task module which can leverage the Single Sign-On capability provided by the Microsoft Teams client out of the box.

But we also saw that in order to consume any back-end API in a secure way, like, for example, Microsoft Graph, we need to leverage the On-Behalf-Of flow in the back-end API that we will have to create and provide, backing the Teams tab or the Teams task module that we create with Yo Teams generator. In this video, we will see how we can create such a kind of back-end API.

First of all, let me explain you the architecture that we will leverage. Imagine that we have the Microsoft Teams client in which we have a custom Team tab, for example, built with Yo Teams generator. In the Team tabs, as we already saw last week, we can use the Microsoft Teams SDK, making a getAuthToken() method invocation in order to get an access token inside the Teams tab custom implementation. Well, eventually the user will have to sign in, but on average there will be the Single Sign-On experience. The very first time, if the consent is required, the user will have to consent to access our API, and it will happen through Azure Active Directory under the cover. Then the Microsoft Teams client will make a request for a delegated access token in order to being able to act in the name of the currently connected user, and Azure Active Directory will provide the delegated access token back to the Microsoft Teams client, which will provide that access token to our tab custom logic so that we will be able to have a delegated access token in the name of the currently connected user.

Now we can have a back-end API, which could be, for example, an Azure function to which we can provide as an authorization header the access token that we have just got back from the getAuthToken() method. The Azure function will be able to use the On-Behalf-Of flow talking with Azure Active Directory in the back end in order to get back a new delegated access token still in the name of the currently connected user, but in order to consume any other back-end API like, for example, Microsoft Graph or SPO REST or such kind of stuff.

Let’s imagine that we want to consume the Microsoft Graph. Providing the new access token that we’ve got through the OBO flow, we can then consume the Microsoft Graph in the name of the currently connected user, and we can provide back from the back-end API to the Teams tab the data and the values requested by the custom logic in the Teams tab. It is quite complex architecture but really powerful because we can have a custom Teams tab able to consume a back-end API and the workloads of Microsoft 365 in the name of the currently connected user.

In order to create such kind of solution, as I said, I usually consider using an Azure function, which can eventually be secured from an authentication point of view still using Azure Active Directory and based on the access token that we get in the request from the Teams tab. I’m also going to show you how you can use the PnP Core SDK, which is a new library that we are going to release as PnP, which is Graph first, so we consume Microsoft Graph first, and which internally provides an out-of-the-box implementation of the OBO flow, so the On-Behalf-Of flow, using MSAL, the Microsoft Authentication Library. Let’s move to the demo environment, and let’s see the demo in action.

First of all, let’s have a look at the Teams tab with Single Sign-On in place. This tab will retrieve using the flow that I just showed you some information about a target site collection in SharePoint Online and about the currently connected user consuming the back-end API. The site that I’m using is this one, which is in SharePoint Online within the same tenant, and if we switch to the source code of the Teams tab generated with Yo Teams, we can see that in the state object, I defined a few properties in order to hold the value of the web ID, web title, user principal name, and user title. I will use those information in the render method of my React component for the Teams tab. In the componentWillMount method of my React component, I simply use the getAuthToken() method that we saw already last week in episode number 132.

With the token that we get back from the getAuthToken(), we simply use a back-end service that I created in my solution, which will provide a getSPOInformation method which accepts as an input argument the token and which will give me back a result object which will provide me the web ID, the web title, and all the other information that I want to show. If we go to have a look at this service, we can see that the ConsumeSPOService in the getSPOInformation method will simply use a function URL as the target endpoint. We’ll do a fetch using the function URL, it will be a get request providing in the address the accept application JSON to get back a JSON response and the authorization header with a bearer token with the value of the token that we have just got through the getAuthToken() method.

Then we simply return back the JSON object that we get through the REST request. If I switch to the Azure function, I can show you the implementation of the Azure function. This is a function which will use the PnP core SDK first of all, and the PnP core SDK is based on the dependency injection model. So in this function, I have a startup class where I simply inject the PnP core services. Of course, I need to reference in the NuGet packages the PnP Core SDK library, so I am referencing the PnP.Core.Auth library, which internally uses also and depends on the PnP Core library. By doing that in my Azure Function, I can simply read some settings from the configuration of my Azure function, what will be the target site URL, the client ID and the tenant ID and the client secret of my application, which will be used to do the On-Behalf-Of flow.

Then I get from the request, and specifically from the request header of type authorization, the value of the bearer token, so the access token. Using the OnBehalfOfAuthenticationProvider that we provide in PnP Core SDK, I can easily provide the client ID and the tenant ID as well as the client secret of an application registered in Azure Active Directory, which will work using the On Behalf flow and which will accept an access token to use to make the On Behalf flow request. By doing that, and by using the PnPContextFactory that we have in PnP core SDK, I can easily connect to a target site providing this authentication provider, which will do for me under the cover all the On-Behalf-Of flow handshake. I will get back a context object which I can easily use to access the web object and to get asynchronously the ID, the title, and the current user, and about the current user I can get, again, asynchronously the title and the user principal name so that I can build a result and return it as a JSON result of my Azure Function.

Of course, the Azure Function, if we switch to Azure, is configured on Azure. It will provide my function in the list of functions available in the Function app. If we go to the configuration, we will have all of the settings that we need to access the Azure Active Directory in the On-Behalf-Of flow, so the client ID, the client secret, the tenant ID, as well as the target site URL that we want to use consuming the back-end API. In the CORS section, I have to configure that the endpoint of my Teams tab, which is the one hosted in ngrok right now, will have to be allowed to make a REST Request targeting my API. Of course, in order to complete this reasoning, I also need to show you under portal.azure.com that under Azure Active Directory, if I go here, under App registrations, I have an application which will be the Yo Teams SSO Tab application, which is the one again we saw in episode 132 last week, and which we use to get the Single Sign-On functionality in place in the Teams tab.

But I also configured that application to also have the delegated permission requests to read all the sites in my SharePoint Online, so that by doing that, I can use the On Behalf flow and I can get the permission to access SharePoint Online in the back end based on the access token that I get in the front end in the Teams client that we did the getAuthToken() method. And, simple as that, we will provide the access token to the back-end API, the back-end API will get the access token in the request and will use it for the On-Behalf-Of flow in order to get access to the target site or to the target endpoint of Microsoft Graph.

Like always, thank you for watching this video. I hope you found it interesting and I’m really looking forward to seeing you next week. And remember, subscribe to this channel. Thank you.