Fetching Teams User Info from Microsoft Graph with TeamsFx SDK
Tags: msteams, tutorial, node, vscode
Published: 2021-07-29 21:26:21

## 😘 TL;DR

First of all, this tutorial became far longer than I initially intended, so I decided to include this quick summary of the article:

- There are various tools and SDKs for Teams app development so you need to pick the right & preferred tools!
- TeamsFx is a great tool when you build app that uses Microsoft Graph API for fetching data, such as basic user info
- TeamsFx handles the OAuth 2.0 authorization code grant flow, getting an access token, and use the token to make Graph API calls
- Use the Graph wrapper, `client.api(path).get` to make the call

Now, proceed to the main content!

---

In my [previous tutorial](https://dev.to/azure/using-vs-code-toolkit-for-teams-app-development-2o0g), I showed you how to use a VS Code extension, Teams Toolkit to start building a Teams bot. In this tutorial, I walk you through the sample bot app from Toolkit and introduce you Microsoft Graph and TeamsFx. But before getting into the code, let me quickly explain about development tools.

## 🔧 Teams Development Tools

In my other Microsoft Teams-related tutorials, I mentioned **Teams SDK** to build Tabs core user interface, **Bot Framework** to build bots and messaging extensions, **Adaptive Cards** for UI components in messages, and **Teams Toolkit** VSCode extension for quick scaffolding all types of Teams apps.

Some of the tools are not only created for Teams development, but for multiple Microsoft products. Here's a quick table of available tools for Teams:

| Product | What it is | What it does for Teams app development | What else it is used for |
| --- | --- | --- | --- |
| [Teams SDK](https://docs.microsoft.com/javascript/api/overview/msteams-client?view=msteams-client-js-latest&WT.mc_id=m365-35902-timura) (Teams.js) | Teams Client SDK | Tabs development (Front-end) | (Teams-specific) |
| [Bot Framework](https://dev.botframework.com/?WT.mc_id=m365-35902-timura) | Bot SDK | Teams bots development | Web & mobile chat, Skype, Facebook, Amazon Alexa, Slack, Twilio, etc. |
| [Adaptive Cards](https://adaptivecards.io/?WT.mc_id=m365-35902-timura) | Platform-agnostic UI snippets (JSON) | Rich-format messages & cards | Web & mobile UI, Outlook messages, etc. |
| [App Studio](https://docs.microsoft.com/microsoftteams/platform/concepts/build-and-test/app-studio-overview/?WT.mc_id=m365-35902-timura) | Visual tool | Create & configure Teams app packages | (Teams-specific) |
| [Teams Toolkit](https://marketplace.visualstudio.com/items?itemName=TeamsDevApp.ms-teams-vscode-extension&WT.mc_id=m365-35902-timura) | VS Code Extension | Register & configure app. App scaffold | (Teams-specific) |
| [TeamsFx](https://docs.microsoft.com/javascript/api/@microsoft/teamsfx/?view=msteams-client-js-latest&WT.mc_id=m365-35902-timura) | SDK & CLI | Implement identity and access to Graph resources | (Teams-specific) |
| [Microsoft Graph](https://docs.microsoft.com/graph/?WT.mc_id=m365-35902-timura) | REST API | Provides access to data stored across Microsoft 365 services, including Teams | Access & manage calendar, mail, oneDrive, etc. |
| [Developer Portal for Microsoft Teams](https://dev.teams.microsoft.com/home) (Preview) | Web tool | Configurations & references | (Teams-specific) |

*There are more tools you can use for Teams, but I am not covering everything in this tutorial!*

Usually during development, you would use a combination of some of them. For example, in this tutorial we are going to use Teams Toolkit, Bot Framework (that includes wrapper methods for Adaptive Cards), and TeamsFx (that includes Graph API wrappers). 

Now, let's start off where we left off in the previous tutorial, [Using VS Code Teams Toolkit Extension for Teams App Development](https://dev.to/azure/using-vs-code-toolkit-for-teams-app-development-2o0g).

---

## 🤖 Using Microsoft Bot Framework

After you build and run the template code from the Toolkit, let's take a look at **bot** directory, where the bot code is stored.

![Screenshot - VS Code](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4ngd7tbfbq2y3ra1iq7d.png)

Now, let's walk through the template code together quickly—

### 📄 bot/index.js

In **index.js**, notice [`botbuilder`](https://docs.microsoft.com/javascript/api/botbuilder/?view=botbuilder-ts-latest&WT.mc_id=m365-35902-timura) (Microsoft Bot Framework) is imported.

This is where the adapter is created so that it allows your bot to communicate with the user and send responses.

```js
const { BotFrameworkAdapter, ConversationState, MemoryStorage, UserState } = require("botbuilder");
...
const adapter = new BotFrameworkAdapter({
  appId: process.env.BOT_ID,
  appPassword: process.env.BOT_PASSWORD,
});
```
*Teams Toolkit already has handled registering your bot to Azure Active Directory so you don't need to manually configure your Bot ID and password* 🙌

Also, `Restify` is set up to HTTP server and routing HTTP requests.

```js
const server = restify.createServer();
server.listen(process.env.port);

// Listen for incoming requests.
server.post("/api/messages", async (req, res) => {
  await adapter.processActivity(req, res, async (context) => {
    await bot.run(context);
  })...
});
```

To simplify the tutorial, I am not explaining how to manage states, and what *turn* means. If you would like to learn the concept of bot, read [How bot works](https://docs.microsoft.com/azure/bot-service/bot-builder-basics?view=azure-bot-service-4.0&WT.mc_id=m365-35902-timura).

### 📄 bot/teamsBot.js

The **bot/teamsBot.js** is the main entry point for the bot.

The `TeamsBot` class is being created here. Its `run` function is called by the adapter and routed to bot's activity logic through `Restify` middleware (from **index.js**). 

In the constructor, it overrides some of the [`TeamsActivityHandler`](https://docs.microsoft.com/javascript/api/botbuilder/teamsactivityhandler?view=botbuilder-ts-latest&WT.mc_id=m365-35902-timura) methods by extending it to customize bot behavior and message text.

```js
class TeamsBot extends TeamsActivityHandler {
  ...
  constructor(conversationState, userState, dialog) {
    super();
    ...

    this.onMessage(async (context, next) => {
      ...
    });

    this.onMembersAdded(async (context, next) => {
      ...
    });

  }
}
```

For example, methods overridden are `onMessage` and `onMembersAdded` in this sample. They register the event handlers for the `message` event, emitted for every incoming message activity, and `MembersAdded` event emitted when a new member is added to the conversation, respectively.

#### Message event

When a message is sent to bot from a user (like, `show` command), `onMessage` gets triggered.

```js
this.onMessage(async (context, next) => {
  await this.dialog.run(context, this.dialogState);
  await next();
});
```
Then, it runs the `Dialog` with the new message Activity.

### 📄 bot/dialogs/mainDialogs.js

```js
const { Dialog, DialogSet, DialogTurnStatus, WaterfallDialog } = require("botbuilder-dialogs");
```

The [dialogs library](https://docs.microsoft.com/azure/bot-service/bot-builder-concept-dialog?view=azure-bot-service-4.0&WT.mc_id=m365-35902-timura) 💬 provides a state-based model to manage a long-running conversation with the user. A dialog performs a task that can represent conversational thread. 


---

Okay, this was a quick walk-through of what some of the code does. Now, let's get to the main topic, **TeamsFx** and **Graph**.

## 🪅 What is TeamsFx?

TeamsFx is a framework, created to make the integrations of **Microsoft Graph API** and implementing identity and access with Teams easier. For example, it handles the OAuth 2.0 authorization code grant flow, getting an access token, and use the token to make Graph API calls.

### Microsoft Graph API

So what is [Microsoft Graph API](https://docs.microsoft.com/graph/?WT.mc_id=m365-35902-timura), first of all? It is a REST API lets you to connect the data from Microsoft 365 services.

![Microsoft Graph API](https://docs.microsoft.com/graph/images/microsoft-graph.png)

M365 platform holds various people-centric data and insights across the Microsoft cloud services, including Teams, Outlook, Calendars, etc. It means whenever you want to access to the data within your Teams app, you need to use Graph to access the data. 

For example, in this sample app, when a user asks a bot to display the user's info with the `show` command, the app make an API call to fetch the data from Graph.

## 🪅 Using TeamsFx to call Graph API

In **bot/dialogs/mainDialogs.js**, both TeamsFx and Graph libraries are imported:

```js
const {createMicrosoftGraphClient, loadConfiguration, OnBehalfOfUserCredential, TeamsBotSsoPrompt} = require("@microsoft/teamsfx");
const { ResponseType } = require("@microsoft/microsoft-graph-client");
```
### 🔏 User Authentication & Authorization

The app creates and authenticates a `MicrosoftGraphClient` by calling `loadConfiguration()`. 

Then, a new instance of `TeamsBotSsoPrompt` is added as a named dialog. `TeamsBotSsoPrompt` is integrated with Bot Framework to simplify the authentication process for bots:

```js
loadConfiguration();
dialogs.add(
  new TeamsBotSsoPrompt("TeamsBotSsoPrompt", {
    scopes: ["User.Read"],
  })
);
```

The `scopes` are the types of permission it requires to call Graph APIs for Teams. The resource-specific permissions are granular and define what an application can do within a specific resource.

There are various permission scopes that can *read* or *write* (create, edit, delete). For instance, `User.Read` is the scope needed to read users info, as the name suggests. And to enable the permissions, the app must ask the user for their consent.

This operation creates a new prompt that leverages Teams Single Sign On (SSO) support for bot to automatically sign in user to receive OAuth token 🏅.

![Screenshot - permissions dialog](https://res.cloudinary.com/practicaldev/image/fetch/s--h3bHmAbq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4r80t4cvr4fdxt9vyx3k.png)

*Authentication and authorization are big topics here. I would need another tutorial to explain deeply about Microsoft identity platform. In the meantime, please read [Authentication and authorization basics for Microsoft Graph](https://docs.microsoft.com/graph/auth/auth-concepts/?WT.mc_id=m365-35902-timura).*

### 📇 Calling Graph API

In the app, when a user sends the "show" command to the bot, the app calls an API from Graph to fetch the user info. (The app asks the user a permission by popping up a SSO window before fetching the user's info, as explained in the previous section.)

Every API call requires the access token 🏅 that has been acquired at the SSO sign-in process. (The token is attached in the Authorization header of the request). 

Also, to access the Microsoft Graph API for Teams, you will need the Teams credentials to do authentication to create a Graph client object.

3 credential classes that are used to help simplifying authentication in TeamsFx:

- `TeamsUserCredential` - Teams current user's identity. Using this credential will request user consent at the first time. 
- `M365TenantCredential` - Microsoft 365 tenant identity. It is usually used when user is not involved like time-triggered automation job. 
- `OnBehalfOfUserCredential` - on-behalf-of flow. It needs an access token and you can get a new token for different scope. 

For bot scenarios, we are using `OnBehalfOfUserCredential` here:

```js
const oboCredential = new OnBehalfOfUserCredential(tokenResponse.ssoToken);
const graphClient = createMicrosoftGraphClient(oboCredential, ["User.Read"]);
```
Now, you have authentication setup and an instance of Graph client, you can finally begin to make calls to the service! 

This is how you can fetch the basic user information, then making the bot to send a message to Teams client:

```js
const me = await graphClient.api("/me").get();

if (me) {
  await stepContext.context.sendActivity(
  `You're logged in as ${me.displayName} and your job title is: ${me.jobTitle}`
  );
 ...

```

Now this is the simplified flow of what you have just learned:

![Teams bot flow](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/x77ebyoyygnxmij1cuh2.png)

[Build and run](https://dev.to/azure/using-vs-code-toolkit-for-teams-app-development-2o0g#running-a-sample-bot-locally) on Teams client if you haven't. Try the `show` command to ask the bot to display your info. 
When everything goes well, this is how it looks like:

![Screenshot - bot showing user info](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jjn7n2z1dy9vx6557lvu.png)

Ta-da 🎉

## 🧺 More with Graph

Try making more Graph calls with the `api` method. All requests start with `client.api(path)` and end with an action, `get` or `post`:

To get the Teams group the user have joined:
```js
const profile = await graphClient.api("me/joinedTeams").get();
```

The response gives you a list of groups including the group IDs.

To get the members of a Teams group:
```js
const profile = await graphClient.api("groups/{Teams group ID}/members").get;
```

Also, try [Graph Explorer](https://developer.microsoft.com/graph/graph-explorer/?WT.mc_id=m365-35902-timura) to test out the REST API and visualize the response!

![Screenshot - Graph Explorer](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2rd4gan1mhpdmm4jzuyx.png)

---

I hope you enjoyed the tutorial. There are many things you would want to know, such as concepts of bots, OAuth, identity management, etc. but I tried not to make this tutorial too wordy by flooding with info, so I simplified everything by not diving deep into the details on purpose. But hopefully, this tutorial still made sense to you!

If you would like to dive deep, please check out the docs and code repos listed below!

## 📚 Learn More

- [Microsoft Bot Frameworks](https://dev.botframework.com/?T.mc_id=m365-35902-timura)
- Bot Services Documentation - [How bot works?](https://docs.microsoft.com/azure/bot-service/bot-builder-basics?view=azure-bot-service-4.0&tabs=javascript&WT.mc_id=m365-35902-timura)
- [TeamsFx SDK references](https://docs.microsoft.com/javascript/api/@microsoft/teamsfx/?view=msteams-client-js-latest&T.mc_id=m365-35902-timura)
- [TeamsFx GitHub repo](https://github.com/OfficeDev/TeamsFx)
- [Microsoft Graph API](https://docs.microsoft.com/graph/?WT.mc_id=m365-35902-timura)
- [Authentication and authorization basics for Microsoft Graph](https://docs.microsoft.com/graph/auth/auth-concepts/?WT.mc_id=m365-35902-timura)