0% found this document useful (0 votes)
292 views88 pages

Extending Teams

This document provides steps to create an app manifest in Microsoft Teams using App Studio. It includes instructions on installing App Studio, configuring an app manifest, importing an existing package, updating the manifest, and deploying the app. It also describes how to create an SPFx web part and deploy it as a Microsoft Teams app.

Uploaded by

Yo Gin Yunen
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
292 views88 pages

Extending Teams

This document provides steps to create an app manifest in Microsoft Teams using App Studio. It includes instructions on installing App Studio, configuring an app manifest, importing an existing package, updating the manifest, and deploying the app. It also describes how to create an SPFx web part and deploy it as a Microsoft Teams app.

Uploaded by

Yo Gin Yunen
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
You are on page 1/ 88

Exercise 1: Creating an app manifest in Microsoft Teams

Task 1: Install App Studio

App Studio is a Teams app which can be found in the Teams store. Follow this link for direct
download: https://aka.ms/InstallTeamsAppStudio (you can also find the app in the app store).

1. Open a browser and navigate to the https://teams.microsoft.com/. Sign in with


Username [email protected] and Password w#!l4ivA5hM?.

2. Select Apps at the bottom of the left hand bar.

3. In the store, search for App Studio.

4. Select the App Studio tile to open the app install page:


5. Select install.
Once you are in App Studio, select the Manifest editor tab where you can either import an
existing app or create a new app.

Task 2: Configure an app manifest using App Studio

Get sample project files

1. Open Powershell and run the following command:

powershell
mkdir c:/LabFiles/Teams

2. Open PowerShell and navigate to C:/LabFiles/Teams:

powershell
cd c:/LabFiles/Teams

3. To clone the sample project repository, execute the following command:

powershell
git clone https://github.com/OfficeDev/msteams-samples-hello-world-
csharp.git

Build a Teams App Package

1. From the PowerShell command prompt, change to


the C:/LabFiles/Teams/msteams-samples-hello-world-csharp directory by executing
the following command:

powershell
cd c:/LabFiles/Teams/msteams-samples-hello-world-csharp

2. Open the folder in Visual Studio Code by executing the following from the project
directory: code .

3. If Visual Studio code displays a dialog box asking if you want to add required
assets to the project, select Yes.

4. From the Visual Studio Code ribbon, select Terminal > New Terminal.

5. In the terminal, Run the following command to compile the application: dotnet


build

6. After succesfully compiling the solution, the helloworldapp.zip Teams App


package will be generated in the ..\bin\Debug\netcoreapp3.1\ folder.

Import the existing package

1. Open a browser and navigate to the https://teams.microsoft.com/.

2. In the app bar, select … More added apps and then select App Studio.

3. In App Studio, select the Manifest editor tab, then select Import an existing app.


Open the project's C:\labfiles\teams\msteams-samples-hello-world-
csharp\Microsoft.Teams.Samples.HelloWorld.Web\bin\Debug\netcoreapp3.1 folder,
and then open the helloworldapp.zip file.

4. You should now see your imported app which you can now select to open.

Update app manifest

Now you can modify your app manifest here in App Studio.
1. On the App details page update the following under the App names section:
o Short name: Change to First App
o Full name: Change to Learn Microsoft Teams App

2. On the App details page, scroll down to the Descriptions section and enter the


following values:
o Short description: Enter My first custom Teams app
o Full description: Enter a longer description of your choice.**

3. Change the Version to 1.0.1.

4. Now update the tab name by following the steps below:

o In the App Studio navigation pane, select Capabilities > Tabs.

o Locate the only personal tab in the project, and select … > Edit on that tab.
o Change the tab name to My First Tab.

o Select Save to save your changes.

Download and Install app manifest

Once you have the app manifest ready, you will need to download it and then manually upload
it to Teams.

1. Download the modified app manifest.

NOTE: Any changes you make in App Studio aren't saved to your project. To update the
project, download the app package from App Studio. To download the project, in the App
Studio navigation pane select Finish > Test and distribute, and then select Download.

WARNING: Be careful if you choose to update the manifest.json file in your project with the
one in the package downloaded from App Studio. The manifest file in your project contains
placeholder strings that are updated by the build and debugging process.

For instance, the {{HOSTNAME}} placeholder is replaced with the app's hosting URL each time
the package is recreated. Because of this, it's not recommended to replace the
existing manifest.json file with the file generated by App Studio.

2. Now upload the file you downloaded to Teams:

a. From the Teams client, select Apps > Upload a custom app.

b. Browse and upload the updated zip package. Open the app and notice it’s
now reflecting the updates you made.
Task 3: Deploying SPFx web part to Microsoft Teams

Create SPFx web part

1. From Powershell command prompt, create the C:/LabFiles/SharePoint directory:

powershell
mkdir c:/LabFiles/SharePoint

2. From the PowerShell command prompt, change to


the C:/LabFiles/SharePoint directory by executing the following command:

cd c:/LabFiles/SharePoint

3. Make a new directory for your SharePoint project files by executing the following
command:
md SPFxTeamsTab

4. Navigate to the newly created SharePoint directory by executing the following


command:

cd SPFxTeamsTab

5. Then execute the following command to install the Yeoman generator:

npm install -g @microsoft/generator-sharepoint

6. Execute the following command to install Gulp:

npm install -g yo gulp

7. Run the SharePoint Yeoman generator by executing the following command:

yo @microsoft/sharepoint

8. Use the following below to complete the prompts that are displayed:
o What is your solution name?: SPFxTeamsTab
o Which baseline packages do you want to target for your
component(s)?: SharePoint Online only (latest)
o Where do you want to place the files?: Use the current folder
o Do you want to allow the tenant admin the choice of being able to deploy
the solution to all sites immediately without running any feature deployment
or adding apps in sites?: Yes
o Will the components in the solution require permissions to access web
APIs that are unique and not shared with other components in the tenant?:
No
o Which type of client-side component to create?: WebPart
o What is your Web Part name?: SPFx Teams Together
o What is your Web Part description?: SPFx Teams Together description
o Which framework would you like to use?: No JavaScript framework

9. After provisioning the folders required for the project, the generator will install all
the dependency packages using NPM.
10. Open the project in Visual Studio Code

code .

11. Enable the web part to be used in Microsoft Teams:

o Locate and open the


file C:\LabFiles\SharePoint\SPFxTeamsTab\src\webparts\spFXTeamsTogether\S
pFx TeamsTogetherWebPart.manifest.json.

o Within the web part manifest file, locate the property supportedHosts:

"supportedHosts": ["SharePointWebPart"],

o Add another option to enable this web part to be used as a tab in a


Microsoft Teams team:

"supportedHosts": ["SharePointWebPart", "TeamsTab"],

Creating and deploying the Microsoft Teams app package

1. Create a manifest.json file in ./teams folder and use the following below as the


content for the file:

json
{
"$schema": "https://developer.microsoft.com/json-
schemas/teams/v1.5/MicrosoftTeams.schema.json",
"manifestVersion": "1.5",
"packageName": "{{SPFX_COMPONENT_ALIAS}}",
"id": "{{SPFX_COMPONENT_ID}}",
"version": "0.1",
"developer": {
"name": "Parker Porcupine",
"websiteUrl": "https://contoso.com",
"privacyUrl": "https://contoso.com/privacystatement",
"termsOfUseUrl": "https://contoso.com/servicesagreement"
},
"name": {
"short": "{{SPFX_COMPONENT_NAME}}"
},
"description": {
"short": "{{SPFX_COMPONENT_SHORT_DESCRIPTION}}",
"full": "{{SPFX_COMPONENT_LONG_DESCRIPTION}}"
},
"icons": {
"outline": "{{SPFX_COMPONENT_ID}}_outline.png",
"color": "{{SPFX_COMPONENT_ID}}_color.png"
},
"accentColor": "#004578",
"staticTabs": [
{
"entityId": "com.contoso.personaltab.spfx",
"name": "My SPFx Personal Tab",
"contentUrl":
"https://{teamSiteDomain}/_layouts/15/TeamsLogon.aspx?
SPFX=true&dest=/_layouts/15/teamshostedapp.aspx%3Fteams%26personal
%26componentId={{SPFX_COMPONENT_ID}}%26forceLocale={locale}",
"scopes": [
"personal"
]
}
],
"configurableTabs": [
{
"configurationUrl": "https://{teamSiteDomain}
{teamSitePath}/_layouts/15/TeamsLogon.aspx?
SPFX=true&dest={teamSitePath}/_layouts/15/teamshostedapp.aspx
%3FopenPropertyPane=true%26teams%26componentId={{SPFX_COMPONENT_ID}}
%26forceLocale={locale}",
"canUpdateConfiguration": true,
"scopes": [
"team"
]
}
],
"validDomains": [
"*.login.microsoftonline.com",
"*.sharepoint.com",
"spoprod-a.akamaihd.net",
"resourceseng.blob.core.windows.net"
],
"webApplicationInfo": {
"resource": "https://{teamSiteDomain}",
"id": "00000003-0000-0ff1-ce00-000000000000"
}
}

2. Open the manifest.json file.

This file contains multiple strings that need to be updated to match the SPFx component.

The SPFx component properties are found in the web part manifest
file: ./src/webparts/spFxTeamsTogether/SpFxTeamsTogetherWebPart.manifest.json
Use the following table below to determine the values that should be replaced:

Property in SPFx component


manifest.json string
manifest

{{SPFX_COMPONENT_ALIAS}} alias

{{SPFX_COMPONENT_NAME}} preconfiguredEntries[0].title

{{SPFX_COMPONENT_SHORT_DESCRIPT preconfiguredEntries[0].descri
ION}} ption

{{SPFX_COMPONENT_LONG_DESCRIPTI preconfiguredEntries[0].descri
ON}} ption

{{SPFX_COMPONENT_ID}} id
NOTE: Make sure you
update {{SPFX_COMPONENT_ID}} in configurableTabs[0].configurationUrl. You will
likely have to scroll your editor to the right to see it. The tokens surrounded by single curly
braces (for example, {teamSiteDomain}) do not need to be replaced.

3. Create a Microsoft Teams app package by zipping the contents of


the ./teams folder.

Make sure to zip just the contents and not the folder itself. This ZIP archive should contain
3 files at the root (2 images and the manifest.json)

Create and deploy the SharePoint package

1. Open the browser and navigate to your SharePoint Online Tenant-Scoped App
Catalog site.

2. Select the menu item Apps for SharePoint from the left navigation menu.

3. Build the project by opening a command prompt and changing to the root folder
of the project. Then execute the following command:

gulp build
4. Next, create a production bundle of the project by running the following command
on the command line from the root of the project:

gulp bundle --ship

5. Create a deployment package of the project by running the following command on


the command line from the root of the project:

gulp package-solution --ship

6. Locate the file created by the gulp task, found in the ./sharepoint/solution folder


with the name *.sppkg.

a. Drag this file into the Apps for SharePoint library in the browser.

b. In the Do you trust…? dialog box, select the check box Make this


solution available to all sites in the organization and then select Deploy.

This will make the SPFx web part available to all site collections in the tenant,
including those that are behind a Microsoft Teams team.

Testing the SPFx web part in Microsoft Teams

1. Create a new Microsoft Teams team.

a. Using the same browser where you are signed in to SharePoint Online,
navigate to https://teams.microsoft.com/. When prompted, load the web client.

b. If you do not have any teams in your tenant, you will be presented with a
dialog to create a team. If you are not prompted with a dialog, select Join or create a
team at the bottom of the list of teams.

i. On the Create your team dialog box, select Build a team from


scratch.

ii. On the What kind of team will this be? dialog box, select Public.


iii. When prompted, use the name My First Team.

2. Install the Microsoft Teams application as a new tab that will expose the SharePoint
Framework web part in Microsoft Teams:

a. Select the My First Team team previously created.

b. Select the General channel.

3. Add a custom tab to the team using the SPFx web part:

a. At the top of the page, select the + icon in the horizontal navigation.

b. In the Add a tab dialog box, select More Apps.

c. Select the Upload a custom app > Upload for … from the list of app


categories.

d. Select the Microsoft Teams application ZIP file previously created. This is
the file that contains the manifest.json and two image files.

NOTE: After a moment, the application will appear next to your tenant name. You may
need to refresh the page for the app to appear if you are using the browser version of
Microsoft Teams.

4. Select the SPFx Teams Together app.

5. In the SPFx Teams Together dialog box, select Add to a team.

6. In the Select a channel to start using SPFx Teams Together dialog box, make


sure that the General channel is selected and select Set up a tab.

7. The next dialog box will confirm the installation of the app. Select Save.

8. The application should now load in Microsoft Teams within the General channel


under the tab SPFx Teams Together.
Review

In this exercise, you:

 Installed App Studio app in Teams.


 Configured and updated app manifest.
 Deployed a SPFx web part to Microsoft Teams.

Congratulations!

You have successfully completed this exercise. Click Next to adva


Exercise 2: Deploying a Microsoft Teams app

Task 1: Setup Environment for Teams development

Install your development tools

These lessons show how you can get started quickly with the Microsoft Teams Toolkit for Visual
Studio Code.

NOTE: Due to a bug in the latest Microsoft Teams Toolkit for bot development, you will need
to install version 1.1.2.
1. Open Visual Studio Code and select Extensions on the left Activity Bar.

2. Search Microsoft Teams Toolkit on the extensions panel and install the Microsoft


Teams Toolkit.

3. After the latest Microsoft Teams Toolkit is installed, click on the gear icon and
choose Install Another Version.
4. Select 1.1.2.

5. Click on Reload Required to reload Visual Studio Code.


Task 2: Use the Microsoft Teams Toolkit in Visual Studio Code to
set up your first app project

1. In Visual Studio Code, select Microsoft Teams on the left Activity Bar and
choose Create a new Teams app.
2. When prompted, sign in with your Microsoft 365 development account.

3. On the Add capabilities screen, select Tab then Next.


4. Enter a name for your Teams app. (This is the default name for your app and also
the name of the app project directory on your local machine.)

5. Check only the Personal tab option and select Finish at the bottom of the screen
to configure your project.

Review the generated solution

Once the toolkit configures your project, you will have the components to build a basic
personal tab for Teams. The project directories and files display in the Explorer area of Visual
Studio Code.
NOTE: The toolkit automatically creates scaffolding for you in the src directory based on the
capabilities you added during setup.
For example, if you create a tab during setup the App.js file in the src/components directory is
important because it handles the initialization and routing of your app. It calls the Microsoft
Teams SDK to establish communication between your app and Teams.

App ID

Your Teams app ID is needed to configure your app with App Studio.

 You can find the ID in the teamsAppId object, which is located in your


project's package.json file.

Build and run your app

Your Tab will be located in the ./src/components/Tab.js file. This is the TypeScript React


based class for your Tab.

 Locate the render() method and observe the code inside the <div> tag.


typescript
<div>
<h3>Hello World!</h3>
<h1>Congratulations {userName}!</h1>
<h3>This is the tab you made :-)</h3>
</div>

1. Open Terminal in Visual Studio Code. From the Visual Studio Code ribbon
select Terminal > New Terminal.

2. Go to the root directory of your app project and run: npm install.


3. To build your solution run the npm run build command.

o This will transpile your solution into the ./build folder.

Run your app

To run your app you use the npm start command.

This will build and start a local web server for you to test your app. The command will also
rebuild the application whenever you save a file in your project.

Once complete, there's a Compiled successfully! message in the terminal. Your app should now
be running on https://localhost:3000.

Task 3: Sideload an app in Microsoft Teams

Now that you’ve tested your tab, it’s time to run your app inside Microsoft Teams.

1. In Visual Studio Code, press the F5 key to launch a Teams web client.

2. To display your app content in Teams, specify that where your app is running
(localhost) is trustworthy:

a. Open a new tab in the same browser window (Google Chrome by default)
which opened after pressing F5.

b. Go to https://localhost:3000/tab and proceed to the page.


3. Go back to Teams. In the dialog, select Add for me to install your app.

If your Add button is grayed out, and you receive a warning This app is not from your
organization's app catalog, preventing installation of your Teams App, implement the
following process to insure your Tenant has a Sideloading Policy enabled.

Note that this setting may take a few minutes to become in-effect so you may need to close
your browser, wait 10 minutes, and then repeat from Task 3, Step 1 until your Add button is
enabled:
 Access https://admin.teams.microsoft.com
 Login as [email protected] with Password of w#!l4ivA5hM?.
 In the left menu bar select Teams Apps and then Setup Policies.
 Select Global (Org-wide default).
 Switch the Upload custom apps toggle from Off to On.
 Scroll down and then select Save at bottom of screen.

Review

In this exercise, you:

 Utilized Microsoft Teams Toolkit to creates scaffolding and reviewed the result.

 Built and run Teams Tab app in Teams.

Congratulations!

You have successfully completed this exercise. Click Next to advance to the next exercise.
Exercise 3: Creating and using task modules in Microsoft Teams

Task modules allow you to create modal popup experiences in your Teams application.
Inside the popup you can run your own custom HTML/JavaScript code, show an
\<iframe>-based widget such as a YouTube or Microsoft Stream video or display
an https://docs.microsoft.com/en-us/adaptive-cards/.

To create a task module, you will need to create a Teams application for displaying Task
modules.

1. Open Visual Studio Code and select Extensions on the left Activity Bar.

2. Select Microsoft Teams and choose Create a new Teams app.


3. When prompted, sign in with your Microsoft 365 developer account.

4. On the Add capabilities screen, select Tab and Bot then Next.


5. Enter a name for your Teams app. (This is the default name for your app and
also the name of the app project directory on your local machine.)

6. Check the Personal tab option in Configure tab section.

7. Select the Create Bot Registration button to register a bot in Configure


bot section.
8. Select Finish at the bottom of the screen to configure your project.

Task 1: Create a card-based task module


Cards are actionable snippets of content that you can add to a conversation through a bot, a
connector, or app. Using text, graphics, and buttons, cards allow you to communicate with
an audience. we will create a simple Adaptive Card to Teams Tab app project.
1. From Visual Studio Code, open the Tab.js file in
the ..\tabs\src\components\ folder.

2. Locate the method render() add the following functions before it.

typescript
showCardBasedTaskModule() {
let cardJson = {
contentType: "application/vnd.microsoft.card.adaptive",
content: {
type: "AdaptiveCard",
body: [
{
type: "TextBlock",
text: "Here is a ninja cat:",
},
{
type: "Image",
url: "https://adaptivecards.io/content/cats/1.png",
size: "Medium",
},
],
version: "1.0",
},
};
let taskInfo = {
title: null,
height: 510,
width: 430,
url: null,
card: cardJson,
fallbackUrl: null,
completionBotId: null,
};

microsoftTeams.tasks.startTask(taskInfo, (err, result) =&gt; {


console.log(`Submit handler - err: ${err}`);
});
}

3. Continue to locate the method render() and update the contents to match the


following code.

typescript
render() {
return (
<div>
<button
onClick={this.showCardBasedTaskModule}>ShowCard</button>
</div>
);
}

Now, a card-based task module has been added to the Teams Tab app.

Task 2: Create an iframe-based task module

1. From Visual Studio Code, create a folder named models in the service folder.

2. Follow the steps below to create 4 script files in the models folder.

a. Create a file named taskmoduleids.js and copy the following code to


the file.

typescript
const TaskModuleIds = {
YouTube: 'YouTube',
AdaptiveCard: 'AdaptiveCard'
};

module.exports.TaskModuleIds = TaskModuleIds;

b. Create a file named taskmoduleresponsefactory.js and copy the


following code to the file.

typescript
class TaskModuleResponseFactory {
static createResponse(taskModuleInfoOrString) {
if (typeof taskModuleInfoOrString === 'string') {
return {
task: {
type: 'message',
value: taskModuleInfoOrString
}
};
}
return {
task: {
type: 'continue',
value: taskModuleInfoOrString
}
};
}

static toTaskModuleResponse(taskInfo) {
return TaskModuleResponseFactory.createResponse(taskInfo);
}
}
module.exports.TaskModuleResponseFactory = TaskModuleResponseFactory;

c. Create a file named taskmoduleuiconstants.js and copy the following


code to the file.

typescript
const { UISettings } = require('./uisettings');
const { TaskModuleIds } = require('./taskmoduleids');

const TaskModuleUIConstants = {
YouTube: new UISettings(1000, 700, 'YouTube Video',
TaskModuleIds.YouTube, 'YouTube'),
AdaptiveCard: new UISettings(400, 200, 'Adaptive Card: Inputs',
TaskModuleIds.AdaptiveCard, 'Adaptive Card')
};

module.exports.TaskModuleUIConstants = TaskModuleUIConstants;

d. Create a file named uisettings.js and copy the following code to the file.

typescript
class UISettings {
constructor(width, height, title, id, buttonTitle) {
this.width = width;
this.height = height;
this.title = title;
this.id = id;
this.buttonTitle = buttonTitle;
}
}

module.exports.UISettings = UISettings;

3. Create a folder named pages in the service folder.

4. Now you need to create the following HTML file in the pages folder.

a. Create a file named youtube.html and copy the following code to the


file.
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta name="viewport" content="width=device-width" />
<title>YouTube</title>
<script
src="https://statics.teams.cdn.office.net/sdk/v1.5.2/js/MicrosoftTeams.m
in.js" asp-append-version="true"></script>
</head>
<body>
<style>
body {
margin: 0;
}
#embed-container iframe {
position: absolute;
top: 0;
left: 0;
width: 95%;
height: 95%;
padding-left: 20px;
padding-right: 20px;
padding-top: 10px;
padding-bottom: 10px;
border-style: none;
}
&lt;/style&gt;
&lt;script&gt;
microsoftTeams.initialize();

//- Handle the Esc key


document.onkeyup = function (event) {
if ((event.key === 27) || (event.key === "Escape")) {
microsoftTeams.tasks.submitTask(null); //- this will
return an err object to the completionHandler()
}
}&lt;/script&gt;
&lt;div id="embed-container"&gt;
&lt;iframe width="1000" height="700"
src="https://www.youtube.com/embed/r9WQPSaLnaU" frameborder="0"
allow="autoplay; encrypted-media"
allowfullscreen="allowfullscreen"&gt;&lt;/iframe&gt;&lt;/div&gt;
</body>
</html>

5. Open index.js in the service folder, and then add the following code to the end
of the file.

typescript
server.use(express.static('pages'));

6. Open botActivityHandler.js in the service folder, replace all contents with the


following code.

typescript
const {
MessageFactory,
TeamsActivityHandler,
CardFactory,
} = require('botbuilder');
const { TaskModuleUIConstants } =
require('./models/TaskModuleUIConstants');
const { TaskModuleIds } = require('./models/taskmoduleids');
const { TaskModuleResponseFactory } =
require('./models/taskmoduleresponsefactory');

const Actions = [
TaskModuleUIConstants.AdaptiveCard,
TaskModuleUIConstants.YouTube
];

class BotActivityHandler extends TeamsActivityHandler {


constructor() {
super();
this.baseUrl = process.env.BaseUrl;

// See https://aka.ms/about-bot-activity-message to learn more


about the message and other activity types.
this.onMessage(async (context, next) =&gt; {
// This displays two cards: A HeroCard and an AdaptiveCard.
Both have the same
// options. When any of the options are selected,
`handleTeamsTaskModuleFetch`
// is called.
const reply = MessageFactory.list([
this.getTaskModuleAdaptiveCardOptions()
]);
await context.sendActivity(reply);

// By calling next() you ensure that the next BotHandler is


run.
await next();
});
};

handleTeamsTaskModuleFetch(context, taskModuleRequest) {
// Called when the user selects an options from the displayed
HeroCard or
// AdaptiveCard. The result is the action to perform.

const cardTaskFetchValue = taskModuleRequest.data.data;


var taskInfo = {}; // TaskModuleTaskInfo

if (cardTaskFetchValue === TaskModuleIds.YouTube) {


// Display the YouTube.html page
taskInfo.url = taskInfo.fallbackUrl =
'https://01b1d990ea72.ngrok.io/youtube.html';
this.setTaskInfo(taskInfo, TaskModuleUIConstants.YouTube);

} else if (cardTaskFetchValue === TaskModuleIds.AdaptiveCard) {


// Display an AdaptiveCard to prompt user for text, and post
it back via
// handleTeamsTaskModuleSubmit.
taskInfo.card = this.createAdaptiveCardAttachment();
this.setTaskInfo(taskInfo,
TaskModuleUIConstants.AdaptiveCard);
}

return TaskModuleResponseFactory.toTaskModuleResponse(taskInfo);
}

async handleTeamsTaskModuleSubmit(context, taskModuleRequest) {


// Called when data is being returned from the selected option
(see `handleTeamsTaskModuleFetch').

// Echo the users input back. In a production bot, this is where


you'd add behavior in
// response to the input.
await
context.sendActivity(MessageFactory.text('handleTeamsTaskModuleSubmit
: ' + JSON.stringify(taskModuleRequest.data)));

// Return TaskModuleResponse
return {
// TaskModuleMessageResponse
task: {
type: 'message',
value: 'Thanks!'
}
};
}

setTaskInfo(taskInfo, uiSettings) {
taskInfo.height = uiSettings.height;
taskInfo.width = uiSettings.width;
taskInfo.title = uiSettings.title;
}

getTaskModuleAdaptiveCardOptions() {
const adaptiveCard = {
$schema: 'http://adaptivecards.io/schemas/adaptive-
card.json',
version: '1.0',
type: 'AdaptiveCard',
body: [
{
type: 'TextBlock',
text: 'Task Module Invocation from Adaptive Card',
weight: 'bolder',
size: 3
}
],
actions: Actions.map((cardType) =&gt; {
return {
type: 'Action.Submit',
title: cardType.buttonTitle,
data: { msteams: { type: 'task/fetch' }, data:
cardType.id }
};
})
};

return CardFactory.adaptiveCard(adaptiveCard);
}

createAdaptiveCardAttachment() {
return CardFactory.adaptiveCard({
version: '1.0.0',
type: 'AdaptiveCard',
body: [
{
type: 'TextBlock',
text: 'Enter Text Here'
},
{
type: 'Input.Text',
id: 'usertext',
placeholder: 'add some text and submit',
IsMultiline: true
}
],
actions: [
{
type: 'Action.Submit',
title: 'Submit'
}
]
});
}
}

module.exports.BotActivityHandler = BotActivityHandler;

Task 3: Invoke a task module from a tab

1. Open Terminal in Visual Studio Code. From the Visual Studio Code ribbon
select Terminal > New Terminal.

2. Navigate to the tabs directory by running the command cd tabs command.

3. Run npm install to install all dependent packages for the Teams tab.

4. Run npm start to start the app.

5. In Visual Studio Code, press the F5 key to launch a Teams web client.


6. To display your app content in Teams, specify where your app is running
(localhost) is trustworthy:

a. Open a new tab in the same browser window (Google Chrome by


default) which opened after pressing F5.

b. Go to https://localhost:3000/tab and proceed to the page.

7. Go back to Teams. In the dialog, select Add for me to install your app.

8. Select the ShowCard button to invoke the task module you just created.

9. Go back to the Visual Studio Code project. Stop the running project by
selecting Ctrl + C.

Task 4: Invoke a task module from a bot

1. To invoke, open a command prompt and execute the following command:

powershell
ngrok http -host-header=rewrite 3978
This will start ngrok and will tunnel requests from an external ngrok url to your
development machine on port 3978. Copy the https forwarding address. In the example
below that would be https://787b8292.ngrok.io. You will need this later.

1. Return to Visual Studio Code, and then Open a new Terminal.

2. Navigate to the service directory by executing the cd service command.

3. Run npm install to install all dependent packages for the Teams tab.

4. Run npm start to start the bot service.

5. In Visual Studio Code, press the F5 key to launch a Teams web client.

6. In the dialog, select Add for me to install your app.


7. In the app bar, select … More added apps and then select App Studio.

8. In App Studio, select the Manifest editor tab, then select the app you just
installed.

9. To edit manifest file, select Bots under Capabilities section in left menu.

10. For the Messaging endpoint URL, use the current https URL you were given
by running ngrok and append it with the path /api/messages. It should look similar
to https://{subdomain}.ngrok.io/api/messages

11. In the app bar, select … More added apps and then select your just installed
app.

12. Type Hello in chat to invoke the task module you just created from the Bot.

Review
In this exercise, you learned how to use task modules to create modal popup experiences in
your Teams application.

Congratulations!

You have successfully completed this exercise. Click Next to advance to the next exercise.

PreviousNext: Exercise 4: Creating...


Exercise 4: Creating webhooks in Microsoft Teams

Webhooks can be used to connect web services to channels and teams in Teams.

You can create two types of webhooks—incoming and outgoing. Incoming webhooks


allow you to connect a channel to a service and outgoing webhooks allow you to send
messages to a service.

Task 1: Setting up a custom incoming webhook


These steps explain how to send a card to a connector.

1. In Microsoft Teams, select the Apps icon located in the left navigation.


Select Connectors then select Incoming Webhook.

2. From the dialog, select Add to a team.


3. From the Select a channel to start using Incoming Webhook, select
the General channel of the Training Content team.
4. Click on the Set up a connector button.

5. Provide a name. Optionally, upload an image avatar for your webhook and then
click Create.
6. The dialog window will present a unique URL that will map to the
channel. Copy and save the URL—you will need to provide it to the outside service.

7. Select the Done button. The webhook will now be available in the team


channel.
8. The Incoming Webhook should now be available in the Configured section.

Task 2: Post a message to the webhook using PowerShell

1. From the PowerShell prompt, enter the following command and replace


the <YOUR WEBHOOK URL> with the URL you copied from the previous steps when you
setup your incoming webhook.

powershell
Invoke-RestMethod -Method post -ContentType 'Application/Json' -Body
'{"text":"Hello World!"}' -Uri <YOUR WEBHOOK URL>

2. If the POST succeeds, you should see a simple displayed output by Invoke-
RestMethod.
3. Check the Microsoft Teams channel associated with the webhook URL. You
should see the new card posted to the channel.

Review
In this exercise, you:

 Used a combination of coding tools and user interfaces to create an incoming


webhook.

Congratulations!

You have successfully completed this exercise. Click Next to advance to the next exercise.

PreviousNext: Exercise 5: Creating...


Exercise 5: Creating custom tabs in Microsoft Teams

Task 1: Create a personal tab


This task explains how to use Visual Studio Code and App Studio to create a personal tab.
For this task, you are going to modify the app you created in the first exercise.

Create your personal tab app project

1. In Visual Studio Code, select Microsoft Teams on the left Activity Bar and
choose Create a new Teams app.
2. When prompted, sign in with your Microsoft 365 development account.

3. On the Add capabilities screen, select Tab then Next.


4. Enter a name for your Teams app. (This is the default name for your app and
also the name of the app project directory on your local machine.)

5. Check only the Personal tab option and select Finish at the bottom of the


screen to configure your project.

Build and run the personal tab app

1. Open Terminal in Visual Studio Code. From the Visual Studio Code ribbon
select Terminal > New Terminal.
2. Go to the root directory of your app project and run npm install.

3. Run npm start.

Sideload the personal tab app in Teams

1. In Visual Studio Code, press the F5 key to launch a Teams web client.

2. To display your app content in Teams, specify that where your app is running
(localhost) is trustworthy:

a. Open a new tab in the same browser window (Google Chrome by


default) which opened after pressing F5.

b. Go to https://localhost:3000/ tab and proceed to the page.

3. Go back to Teams. In the dialog, select Add for me to install your app.

4. Please keep running this app in order to complete the next task.

Task 2: Customize your personal tab

Update the personal tab content page

1. Go to the src/components directory and open Tab.js. Locate


the render() function and paste your content inside return() (as shown).

html
<div>
<h1>Important Contacts</h1>
<ul>
<li>Help Desk: <a
href="mailto:[email protected]">[email protected]</a></li>
<li>Human Resources: <a
href="mailto:[email protected]">[email protected]</a></li>
<li>Facilities: <a
href="mailto:[email protected]">[email protected]</a></li>
</ul>
</div>
2. Add the following rule to App.css so the email links are easier to read no matter
which theme is used.

css
a {
color: inherit;
}

3. Save your changes. Go to your app's tab in Teams to view the new content.

Update the personal tab theme

Good apps feel native to Teams, so it's important your tab blends with the Teams theme
your users prefer: default (light), dark, or high contrast. As you might have noticed in the
last screenshot, your tab still has a light background when the client's using the dark theme.
This is not a recommended user experience.

1. Open tab.js with Visual Studio Code, and then insert the following theme
change handler immediately after the microsoftTeams.getContext() call.
typescript
microsoftTeams.registerOnThemeChangeHandler(theme => {
if (theme !== this.state.theme) {
this.setState({ theme });
}
});

1. Replace render() method with the following code.


typescript
render() {
const isTheme = this.state.theme;

let newTheme;

if (isTheme === "default") {


newTheme = {
backgroundColor: "#EEF1F5",
color: "#16233A"
};
} else {
newTheme = {
backgroundColor: "#2B2B30",
color: "#FFFFFF"
};
}

return (
<div style={newTheme}>
<h1>Important Contacts</h1>
<ul>
<li>Help Desk: <a
href="mailto:[email protected]">[email protected]</a></li>
<li>Human Resources: <a
href="mailto:[email protected]">[email protected]</a></li>
<li>Facilities: <a
href="mailto:[email protected]">[email protected]</a></li>
</ul>
</div>
);
}

1. Check your tab in Teams. The appearance should closely match the dark theme.
Well done! You have a Teams app with a personal tab that makes it easier to find important
contacts in your organization.

Task 3: Create a group/Teams channel tab


In this task, you'll build a basic channel tab (also known as a group tab), which is a full-
screen page for a team channel or chat. Unlike a personal tab, users can configure some
aspects of this kind of tab (for example, rename the tab so it's meaningful to their channel).

Create your group tab app project

1. In Visual Studio Code, select Microsoft Teams on the left Activity Bar and
choose Create a new Teams app.
2. When prompted, sign in with your Microsoft 365 development account.

3. On the Add capabilities screen, select Tab then Next.


4. Enter a name for your Teams app. (This is the default name for your app and
also the name of the app project directory on your local machine.)

5. Check the Personal tab and Group or Teams channel tab options.

6. Select Finish at the bottom of the screen to configure your project.

Task 4: Customize your group tab

Update the group tab content page


1. Go to the src/components directory and open Tab.js. Locate
the render() function and paste your content inside return() (as shown).

html
<div>
<h1>Important Contacts</h1>
<ul>
<li>Help Desk: <a
href="mailto:[email protected]">[email protected]</a></li>
<li>Human Resources: <a
href="mailto:[email protected]">[email protected]</a></li>
<li>Facilities: <a
href="mailto:[email protected]">[email protected]</a></li>
</ul>
</div>

2. Add the following rule to App.css so the email links are easier to read no matter
which theme is used.

css
a {
color: inherit;
}

Update the tab configuration page

1. Go to the src/components directory and open TabConfig.js. Locate


the render() function and paste your content inside return() (as shown).

javascript
<div>
<h1>Add My Contoso Contacts</h1>
<div>
Select <b>Save</b> to add our organization''s important contacts
to this workspace.
</div>
</div>

2. In TabConfig.js, go to microsoftTeams.settings.setSettings. Add


the suggestedDisplayName property with the tab name you want to display by default
(as shown). Use the provided name or create your own. (By default, users to change
the name if they want.)

javascript
microsoftTeams.settings.setSettings({
"contentUrl": "https://localhost:3000/tab",
"suggestedDisplayName": "Team Contacts"
});

Build and run the group tab app

1. Open Terminal in Visual Studio Code. From the Visual Studio Code ribbon
select Terminal > New Terminal.

2. Go to the root directory of your app project and run npm install.

3. Run npm start.

Sideload the group tab in Teams

1. In Visual Studio Code, press the F5 key to launch a Teams web client.

2. To display your app content in Teams, specify that where your app is running
(localhost) is trustworthy:

a. Open a new tab in the same browser window (Google Chrome by


default) which opened after pressing F5.

b. Go to https://localhost:3000/ tab and proceed to the page.

3. Go back to Teams. In the dialog, select Add to a team or Add to a chat and


locate a channel or chat you can use for testing.

4. Select Set up a tab. The configuration page displays in a dialog.


5. Select Save to configure the tab. The content page displays.

Well done! You have a Teams app with a tab for displaying useful content in channels and
chats.
Review
In this exercise, you:

 Created a personal tab.


o Created a personal tab app project.
o Customize the personal tab.
o Installed and tested the tab.
 Created a group/Teams channel tab.
o Created a group/Teams channel tab app project.
o Customize the group/Teams channel tab.
o Customize tab configuration page.
o Installed and tested the tab.

Congratulations!

You have successfully completed this exercise. Click Next to advance to the next exercise.

PreviousNext: Exercise 6: Creating...


Exercise 6: Creating messaging extensions in Microsoft Teams

Messaging extensions allow users to interact with your web service through buttons and
forms in the Microsoft Teams client. They can search, or initiate actions, in an external
system from the compose message area, the command box, or directly from a message.
You can then send the results of that interaction back to the Microsoft Teams client,
typically in the form of a richly formatted card

Task 1: Create a search-based messaging extension


Search commands allow your users to search an external system for information (either
manually through a search box, or by pasting a link to a monitored domain into the
compose message area), then insert the results of the search into a message.

Create your search-based messaging extension project

1. In Visual Studio Code, select Microsoft Teams on the left Activity Bar and
choose Create a new Teams app.
2. When prompted, sign in with your Microsoft 365 development account.

3. On the Add capabilities screen, select Messaging Extension then Next.

4. Select the properties for your project.


o Enter a name for your Teams app. (This is the default name for your app and
also the name of the app project directory on your local machine.)
o Check only the Search-based option in Configure messaging
extension section.
o Select Create Bot Registration to create a new bot.

5. Select Finish at the bottom of the screen to configure your project.

6. Open botActivityHandler to
locate async handleTeamsMessagingExtensionQuery(context, query) method.

The web service will receive a composeExtension/query invoke message that


contains a value object with the search parameters. This invoke is triggered:
o As characters are entered into the search box.
o If initialRun is set to true in your app manifest, you'll receive the invoke
message as soon as the search command is invoked.

Run Ngrok for the search-based messaging extension

1. Open a command prompt and execute the following command:

powershell
ngrok http -host-header=rewrite 3978

This will start ngrok and will tunnel requests from an external ngrok url to your
development machine on port 3978. Copy the https forwarding address (you will need
this for the next steps). For example, it would be similar to https://787b8292.ngrok.io.

Update Bot Framework Messaging Endpoint for the search-based messaging


extension

1. Return to Visual Studio code and select App Studio in Microsoft Teams


Toolkit.

2. When prompted, sign in with your Microsoft 365 account.

3. Select Messaging Extension in left menu.

4. For the Messaging endpoint URL, use the current https URL you were given
by running ngrok and append it with the path /api/messages. It should like something
similar to https://{subdomain}.ngrok.io/api/messages.
Build and run the search-based messaging extension

1. Open Terminal in Visual Studio Code. From the Visual Studio Code ribbon
select Terminal > New Terminal.

2. Go to the root directory of your app project and run npm install.

3. Run npm start.

Deploy the search-based messaging extension to Teams

1. Start debugging the project by selecting the F5 key or select the debug icon in
Visual Studio Code and select the Start Debugging (green arrow) button.

2. Go back to Teams. In the dialog, select Add for me to install your app.

Well done, You now have a search-based Messaging Extensions for searching the registry
for packages matching the search terms.

Task 2: Create an action-based messaging extension


Action commands allow you to present your users with a modal popup to collect or display
information. When they submit the form, your web service can respond by inserting a
message into the conversation directly or by inserting a message into the compose message
area and allowing the user to submit the message. You can even chain multiple forms
together for more complex workflows.

1. In Visual Studio Code, select Microsoft Teams on the left Activity Bar and
choose Create a new Teams app.

2. When prompted, sign in with your Microsoft 365 account.

3. On the Add capabilities screen, select Messaging Extension then Next.

4. Select the properties for your project.


o Enter a name for your Teams app. (This is the default name for your app and
also the name of the app project directory on your local machine.)
o Check only the Action-based option in Configure messaging
extension section.
o Select Create Bot Regisstration to create a new bot.

5. Select Finish at the bottom of the screen to configure your project.

Run Ngrok for the action-based messaging extension

1. Ooen a command prompt to execute the following command:


powershell
ngrok http -host-header=rewrite 3978
This will start ngrok and will tunnel requests from an external ngrok url to your
development machine on port 3978. Copy the https forwarding address (you will need this
for the next steps). For example, it would look similar to https://787b8292.ngrok.io.

Update Bot Framework Messaging Endpoint for the action-based messaging


extension

1. Return to Visual Studio code and select App Studio in Microsoft Teams


Toolkit.

2. When prompted, sign in with your Microsoft 365 account.

3. Select Messaging Extension in left menu.


4. For the Messaging endpoint URL, use the current https URL you were given
by running ngrok and append it with the path /api/messages. It should look similar
to https://{subdomain}.ngrok.io/api/messages.

Build and run the action-based messaging extension

1. Open Terminal in Visual Studio Code. From the Visual Studio Code ribbon
select Terminal > New Terminal.

2. Go to the root directory of your app project and run npm install.

3. Run npm start.

Deploy the action-based messaging extension to Teams

1. Start debugging the project by selecting the F5 key or select the debug icon in
Visual Studio Code and click the Start Debugging green arrow button.

2. Go back to Teams. In the dialog, select Add for me to install your app.

Well done, You have a action-based Messaging Extensions for submitting a compose
message to your bot.

Review
In this exercise, you:

 Created a search-based messaging extension.


 Created a action-based messaging extension project.

Congratulations!

You have successfully completed this exercise. Click Next to advance to the next exercise.

PreviousNext: Exercise 7: Creating a Bot...


Exercise 7: Creating a Bot in Microsoft Teams

Conversational bots allow users to interact with your web service through text, interactive
cards, and task modules. They're incredibly flexible — conversational bots can be scoped to
handling a few simple commands or complex, artificial-intelligence-powered and natural-
language-processing virtual assistants. They can be one aspect of a larger application, or
completely stand-alone.

Task 1: Create a Bots project

1. In Visual Studio Code, select Microsoft Teams on the left Activity Bar and
choose Create a new Teams app.
2. When prompted, sign in with your Microsoft 365 development account.

3. On the Add capabilities screen, select Bots then Next.

4. Select the properties for your project.


o Enter a name for your Teams app. (This is the default name for your app and
also the name of the app project directory on your local machine.)
o Select Create Bot Registration to create a new bot.
5. Select Finish at the bottom of the screen to configure your project.

Task 2: Configure scope for your bot

1. In Visual Studio Code, select App Studio in Microsoft Teams Toolkit.

2. When prompted, sign in with your Microsoft 365 development account.

3. Select Bots under Capabilities section in left menu, and then click Edit button.

4. For the Scope, make sure teams, personal and groupChat options are


checked, and then click Save button to close the popup box.

Note: A conversation is a series of messages sent between your bot and one or more users.
There are three kinds of conversations (also called scopes) in Teams:
- **teams**: Also called channel conversations, visible to all members of the
channel.
- **personal**: Conversations between bots and a single user.

- **groupChat**: Chat between a bot and two or more users. Also enables your bot
in meeting chats.

1. Open a command prompt to execute the following commands.

powershell
ngrok http -host-header=rewrite 3978

This will start ngrok and will tunnel requests from an external ngrok url to your
development machine on port 3978. Copy the https forwarding address. In the example
below that would be https://787b8292.ngrok.io. You will need this later.
2. Reture to Visual Studio Code, for the Messaging endpoint, use the current
https URL you were given by running ngrok and append it with the path
/api/messages. It should like something
work https://{subdomain}.ngrok.io/api/messages.

Task 3: Run your bot

1. Open Terminal in Visual Studio Code. From the Visual Studio Code ribbon
select Terminal > New Terminal.

2. Run npm install to install all dependent packages for the Teams tab.

3. Run npm start to start the app.

4. In Visual Studio Code, press the F5 key to launch a Teams web client.

5. Go back to Teams. In the dialog, you could select Add for me to install the bot
as a personal bot, or you select Add to a team or Add to a chat to install the bot as a a
group/channel bot.

6. Try to send "Hello" to start a conversation with the bot.

7. Go back to the Visual Studio Code project. Stop the running project by
selecting Ctrl + C.

Task 4: Send proactive messages


A proactive message is any message sent by a bot that is not in direct response to a request
from a user.

1. From Visual Studio Code, open the index.js file in the root folder.

2. Locate the code const botActivityHandler = new BotActivityHandler...,


update the contents to match the following code.

javascript
const conversationReferences = {};
const botActivityHandler = new BotActivityHandler(conversationReferences);
3. Add the following code to end of index.js file.

javascript
// Listen for incoming notifications and send proactive messages to
users.
server.get('/api/notify', async (req, res) => {
for (const conversationReference of
Object.values(conversationReferences)) {
await adapter.continueConversation(conversationReference, async
turnContext => {
// If you encounter permission-related errors when sending
this message, see
// https://aka.ms/BotTrustServiceUrl
await turnContext.sendActivity('proactive hello');
});
}
res.setHeader('Content-Type', 'text/html');
res.writeHead(200);
res.write('&lt;html&gt;&lt;body&gt;&lt;h1&gt;Proactive messages have
been sent.&lt;/h1&gt;&lt;/body&gt;&lt;/html&gt;');
res.end();
});

4. Open the botActivityHandler.js file in the root folder.

5. Add a parameter conversationReferences for the constructor method, and


update the contents to match the following code.

javascript
constructor(conversationReferences) {
super();
// Dependency injected dictionary for storing ConversationReference
objects used in NotifyController to proactively message users
this.conversationReferences = conversationReferences;

this.onConversationUpdate(async (context, next) =&gt; {


this.addConversationReference(context.activity);

await next();
});

this.onMembersAdded(async (context, next) =&gt; {


const membersAdded = context.activity.membersAdded;
for (let cnt = 0; cnt &lt; membersAdded.length; cnt++) {
if (membersAdded[cnt].id !== context.activity.recipient.id) {
const welcomeMessage = 'Welcome to the Proactive Bot
sample. Navigate to http://localhost:3978/api/notify to proactively
message everyone who has previously messaged this bot.';
await context.sendActivity(welcomeMessage);
}
}
// By calling next() you ensure that the next BotHandler is run.
await next();
});

/* Conversation Bot */
/* Teams bots are Microsoft Bot Framework bots.
If a bot receives a message activity, the turn handler sees that
incoming activity
and sends it to the onMessage activity handler.
Learn more: https://aka.ms/teams-bot-basics.

NOTE: Ensure the bot endpoint that services incoming


conversational bot queries is
registered with Bot Framework.
Learn more: https://aka.ms/teams-register-bot.
*/
// Registers an activity event handler for the message event, emitted
for every incoming message activity.
this.onMessage(async (context, next) =&gt; {
this.addConversationReference(context.activity);

TurnContext.removeRecipientMention(context.activity);
switch (context.activity.text.trim()) {
case 'Hello':
await this.mentionActivityAsync(context);
break;
default:
// By default for unknown activity sent by user show
// a card with the available actions.
const value = { count: 0 };
const card = CardFactory.heroCard(
'Lets talk...',
null,
[{
type: ActionTypes.MessageBack,
title: 'Say Hello',
value: value,
text: 'Hello'
}]);
await context.sendActivity({ attachments: [card] });
break;
}
await next();
});
/* Conversation Bot */
}

6. Locate the method mentionActivityAsync, and append the following code after


the method.

javascript
addConversationReference(activity) {
const conversationReference =
TurnContext.getConversationReference(activity);
this.conversationReferences[conversationReference.conversation.id] =
conversationReference;
}

7. Run npm start to start the app again.

8. In Visual Studio Code, press the F5 key to launch a Teams web client.

9. In your browser, open the page https://localhost:3978/api/notify to send a


proactive message.

10. A message "proactive hello" will be received in your conversation thread.

Task 5: Authentication flow for bots in Microsoft Teams

Create the resource group

For this Cloud Slice version the Resource Group has been created for you. You can skip
this step and proceed to Create the service plan

The resource group and the service plan aren't strictly necessary, but they allow you to
conveniently release the resources you create. This is good practice for keeping your
resources organized and manageable.

1. In your browser, sign into the https://ms.portal.azure.com/.

2. Sign in with [email protected] and e#BdhDB01!.

3. In the left navigation panel, select Resource groups.

4. In the upper left of the displayed window, select Add tab to create a new


resource group.

5. You'll be prompted to provide the following:

a. Subscription. Use your existing subscription.


b. Resource group. Enter the name for the resource group. An example
could be TeamsResourceGroup. Remember that the name must be unique.

c. From the Region drop-down menu, select East US, or a region close to


your applications.

d. Select the Review and create button. You should see a banner that


reads Validation passed.

e. Select the Create button. It may take a few minutes to create the


resource group.

Create the service plan

1. In the https://ms.portal.azure.com/, on the left navigation panel, select Create a


resource.

2. In the search box, type App Service Plan. Select the App Service Plan card


from the search results.

3. Select Create.

4. You'll be asked to provide the following information:

a. Subscription. You can use an existing subscription.

b. Resource Group. Select the group you created earlier.

c. Name. Enter the name for the service plan. An example could
be TeamsServicePlan. Remember that the name must be unique, within the group.

d. Operating System. Select Windows or your applicable OS.

e. Region. Select East US or a region close to your applications.

f. Pricing Tier. Make sure that Standard S1 is selected. This should be


the default value.
g. Select the Review and create button. You should see a banner that
reads Validation passed.

h. Select Create. It may take a few minutes to create the app service plan.
The plan will be listed in the resource group.

Create the bot channels registration

The bot channels registration registers your web service as a bot with the Bot Framework,
provided you have a Microsoft App Id and App password (client secret).

1. In the Azure portal, under Azure services, select Create a resource.

2. In the search box enter "bot". And in the drop-down list, select Bot Channels
Registration.

3. Select the Create button.

4. In the Bot Channel Registration blade, provide the requested information


about your bot.

5. Open a command prompt to execute the following commands.

powershell
ngrok http -host-header=rewrite 3978

This will start ngrok and will tunnel requests from an external ngrok url to your
development machine on port 3978. Copy the https forwarding address. In the example
below that would be https://787b8292.ngrok.io. You will need this later.

6. Reture to Visual Studio Code, for the Messaging endpoint, use the current
https URL you were given by running ngrok and append it with the path
/api/messages. It should like something
work https://{subdomain}.ngrok.io/api/messages.
7. Click Microsoft App ID and password and then Create New.
8. Click Create App ID in the App Registration Portal link.
9. In the displayed App registration window, click the New registration tab in
the upper left.

10. Enter the name of the bot application you are registering, we
used BotTeamsAuth (you need to select your own unique name).

11. For the Supported account types select Accounts in any organizational


directory (Any Azure AD
directory - Multitenant) and personal Microsoft accounts (e.g. Skype, Xbox
).

12. Click the Register button. Once completed, Azure displays the Overview page
for the application.

13. Copy and save to a file the Application (client) ID value.

14. In the left panel, click Certificate and secrets.

a. Under Client secrets, click New client secret.

b. Add a description to identify this secret from others you might need to create for this
app.

c. Set Expires to your selection.

d. Click Add.
e. Copy the client secret and save it to a file.

15. Go back to the Bot Channel Registration window and copy the App ID and


the Client secret in the Microsoft App ID and Password boxes, respectively.

16. Click OK.

17. Finally, click Create.

After Azure has created the registration resource it will be included in the resource group
list.

Once your bot channels registration is created, you'll need to enable the Teams channel.

1. In the https://ms.portal.azure.com/, under Azure services, select the Bot


Channel Registration you just created.

2. In the left panel, click Channels.

3. Click the Microsoft Teams icon, then choose Save.

Note: The Bot Channels Registration resource will show the Global region even if you
selected West US. This is expected.

Create the identity provider

You need an identity provider that can be used for authentication. In this procedure you'll
use an Azure AD provider; other Azure AD supported identity providers can also be used.

1. In the https://ms.portal.azure.com/, on the left navigation panel, select Azure


Active Directory.

2. In the left panel, select App registrations.


3. In the right panel, select the New registration tab, in the upper left.

4. You'll be asked to provide the following information:

a. Name. Enter the name for the application. An example could be BotTeamsIdentity.
Remember that the name must be unique.

b. Select the Supported account types for your application. Select Accounts in any


organizational directory (Any Azure AD
directory - Multitenant) and personal Microsoft accounts (e.g. Skype, Xbox
).

c. For the Redirect URI:

a. Select Web.

b. Set the URL to https://token.botframework.com/.auth/web/redirect.

d. Select Register.

5. Once it is created, Azure displays the Overview page for the app. Copy and
save the following information to a file:

a. The Application (client) ID value. You'll use this value later as the Client ID when
you register this Azure identity application with your bot.

b. The Directory (tenant) ID value. You'll also use this value later as the Tenant ID to
register this Azure identity application with your bot.

6. In the left panel, select Certificates & secrets to create a client secret for your
application.

a. Under Client secrets, select ➕ New client secret.

b. Add a description to identify this secret from others you might need to create for this
app, such as Bot identity app in Teams.

c. Set Expires to your selection.

d. Select Add.
e. Before leaving this page, record the secret. You'll use this value later as the Client
secret when you register your Azure AD application with your bot.

Configure the identity provider connection and register it with the bot

1. In the https://ms.portal.azure.com/, select your resource group from the


dashboard.

2. Select your bot channel registration link.

3. On the resource page, select Settings.

4. Under OAuth Connection Settings near the bottom of the page, select Add


Setting.

5. Complete the form as follows:

a. Name. Enter a name for the connection. You'll use this name in your bot in the
appsettings.json file. For example BotTeamsAuthADv2.

b. Service Provider. Select Azure Active Directory v2. Once you select this, the


Azure AD-specific fields will be displayed.

c. Client id. Enter the Application (client) ID that you recorded for your Azure identity
provider app in the steps above.

d. Client secret. Enter the secret that you recorded for your Azure identity provider
app in the steps above.

e. Token Exchange URL. Leave this blank.

f. Tenant ID, enter the Directory (tenant) ID that you recorded earlier for your Azure
identity app or common depending on the supported account type selected when you
created the identity provider app. To decide which value to assign follow these criteria:

a. If you selected either Accounts in this organizational directory only


(Microsoft only - Single tenant) or Accounts in any organizational
directory(Microsoft AAD directory - Multi tenant) enter the tenant ID you
recorded earlier for the AAD app. This will be the tenant associated with the users
who can be authenticated.
b. If you selected Accounts in any organizational directory (Any AAD
directory - Multi tenant and personal Microsoft accounts e.g. Skype, Xbox,
Outlook) enter the word common instead of a tenant ID. Otherwise, the AAD app
will verify through the tenant whose ID was selected and exclude personal
Microsoft accounts.

g. For Scopes, enter a space-delimited list of graph permissions this application


requires e.g.: User.Read User.ReadBasic.All

6. Select Save.

Test the connection

1. Select the connection entry to open the connection you just created.

2. Select Test Connection at the top of the Service Provider Connection Setting
panel.

3. The first time you do this will open a new browser window asking you to select
an account. Select the one you want to use.

4. Next, you'll be asked to allow to the identity provider to use your data
(credentials). The following image is an example:
5. Select Accept.

6. This should then redirect you to a Test Connection to Succeeded page.


Refresh the page if you get an error. The following image is an example:

The connection name is used by the bot code to retrieve user authentication tokens.

Prepare the bot sample code

1. In Visual Studio Code, select App Studio in Microsoft Teams Toolkit.

2. When prompted, sign in with your Microsoft 365 development account.

3. On the Add capabilities screen, select Bots then Next.

4. Enter a name for the application, e.g. TeamsBotAuthFlowSample.


5. Select Use an existing bot registered with Bot Framework,

a. Set bot App ID to the bot App ID you saved at the time of the bot channel
registration.

b. Set bot App Password to the customer secret you saved at the time of the bot
channel registration.

6. Select Finish at the bottom of the screen to configure your project.

7. In Visual Studio Code, open .env file, append the following content to the end
of the file, please set \<your-connection-name> to the name of the identity provider
connection you added to the bot channel registration.

connectionName=<your-connection-name>

8. Open index.js in the root folder, and then relace content with the following
code.

javascript
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

// index.js is used to setup and configure your bot

// Import required pckages


const path = require('path');
const express = require('express');

// Import required bot services.


// See https://aka.ms/bot-services to learn more about the different
parts of a bot.
const { BotFrameworkAdapter, MemoryStorage, UserState, ConversationState
} = require('botbuilder');

// Import bot definitions


const { BotActivityHandler } = require('./botActivityHandler');

const { MainDialog } = require('./dialogs/mainDialog');

// Read botFilePath and botFileSecret from .env file.


const ENV_FILE = path.join(__dirname, '.env');
require('dotenv').config({ path: ENV_FILE });

// Create adapter.
// See https://aka.ms/about-bot-adapter to learn more about adapters.
const adapter = new BotFrameworkAdapter({
appId: process.env.BotId,
appPassword: process.env.BotPassword
});

adapter.onTurnError = async (context, error) => {


// This check writes out errors to console log .vs. app insights.
// NOTE: In production environment, you should consider logging this
to Azure
// application insights.
console.error(`\n [onTurnError] unhandled error: ${ error }`);
// Send a trace activity, which will be displayed in Bot Framework
Emulator
await context.sendTraceActivity(
'OnTurnError Trace',
`${ error }`,
'https://www.botframework.com/schemas/error',
'TurnError'
);

// Send a message to the user


await context.sendActivity('The bot encountered an error or bug.');
await context.sendActivity('To continue to run this bot, please fix
the bot source code.');
};

// Define the state store for your bot.


// See https://aka.ms/about-bot-state to learn more about using
MemoryStorage.
// A bot requires a state storage system to persist the dialog and user
state between messages.
const memoryStorage = new MemoryStorage();

// Create conversation and user state with in-memory storage provider.


const conversationState = new ConversationState(memoryStorage);
const userState = new UserState(memoryStorage);

// Create the main dialog.


const dialog = new MainDialog();

// Create bot handlers


const botActivityHandler = new BotActivityHandler(conversationState,
userState, dialog);

// Create HTTP server.


const server = express();
const port = process.env.port || process.env.PORT || 3978;
server.listen(port, () =>
console.log(`\Bot/ME service listening at https://localhost:$
{port}`)
);

// Listen for incoming requests.


server.post('/api/messages', (req, res) => {
adapter.processActivity(req, res, async (context) => {
// Process bot activity
await botActivityHandler.run(context);
});
});

9. Create a new folder named dialogs in the project.

10. Use the following content to create a new file named logoutDialog.js in


the dialogs folder.

javascript
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

const { ActivityTypes } = require('botbuilder');


const { ComponentDialog } = require('botbuilder-dialogs');

class LogoutDialog extends ComponentDialog {


constructor(id, connectionName) {
super(id);
this.connectionName = connectionName;
}
async onBeginDialog(innerDc, options) {
const result = await this.interrupt(innerDc);
if (result) {
return result;
}

return await super.onBeginDialog(innerDc, options);


}

async onContinueDialog(innerDc) {
const result = await this.interrupt(innerDc);
if (result) {
return result;
}

return await super.onContinueDialog(innerDc);


}

async interrupt(innerDc) {
if (innerDc.context.activity.type === ActivityTypes.Message) {
const text = innerDc.context.activity.text.toLowerCase();
if (text === 'logout') {
// The bot adapter encapsulates the authentication
processes.
const botAdapter = innerDc.context.adapter;
await botAdapter.signOutUser(innerDc.context,
this.connectionName);
await innerDc.context.sendActivity('You have been signed
out.');
return await innerDc.cancelAllDialogs();
}
}
}
}

module.exports.LogoutDialog = LogoutDialog;

11. Use the following content to create a new file named mainDialog.js in


the dialogs folder.

javascript
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

const { ConfirmPrompt, DialogSet, DialogTurnStatus, OAuthPrompt,


WaterfallDialog } = require('botbuilder-dialogs');

const { LogoutDialog } = require('./logoutDialog');

const CONFIRM_PROMPT = 'ConfirmPrompt';


const MAIN_DIALOG = 'MainDialog';
const MAIN_WATERFALL_DIALOG = 'MainWaterfallDialog';
const OAUTH_PROMPT = 'OAuthPrompt';

class MainDialog extends LogoutDialog {


constructor() {
super(MAIN_DIALOG, process.env.connectionName);
this.addDialog(new OAuthPrompt(OAUTH_PROMPT, {
connectionName: process.env.connectionName,
text: 'Please Sign In',
title: 'Sign In',
timeout: 300000
}));
this.addDialog(new ConfirmPrompt(CONFIRM_PROMPT));
this.addDialog(new WaterfallDialog(MAIN_WATERFALL_DIALOG, [
this.promptStep.bind(this),
this.loginStep.bind(this),
this.displayTokenPhase1.bind(this),
this.displayTokenPhase2.bind(this)
]));

this.initialDialogId = MAIN_WATERFALL_DIALOG;
}

/**
* The run method handles the incoming activity (in the form of a
DialogContext) and passes it through the dialog system.
* If no dialog is active, it will start the default dialog.
* @param {*} dialogContext
*/
async run(context, accessor) {
const dialogSet = new DialogSet(accessor);
dialogSet.add(this);

const dialogContext = await dialogSet.createContext(context);


const results = await dialogContext.continueDialog();
if (results.status === DialogTurnStatus.empty) {
await dialogContext.beginDialog(this.id);
}
}

async promptStep(stepContext) {
return await stepContext.beginDialog(OAUTH_PROMPT);
}

async loginStep(stepContext) {
// Get the token from the previous step. Note that we could also
have gotten the
// token directly from the prompt itself. There is an example of
this in the next method.
const tokenResponse = stepContext.result;
if (tokenResponse) {
await stepContext.context.sendActivity('You are now logged
in.');
return await stepContext.prompt(CONFIRM_PROMPT, 'Would you
like to view your token?');
}
await stepContext.context.sendActivity('Login was not successful
please try again.');
return await stepContext.endDialog();
}

async displayTokenPhase1(stepContext) {
await stepContext.context.sendActivity('Thank you.');

const result = stepContext.result;


if (result) {
// Call the prompt again because we need the token. The
reasons for this are:
// 1. []If the user is already logged in we do not need to
store the token locally in the bot and worry
// about refreshing it. We can always just call the prompt
again to get the token.
// 2. We never know how long it will take a user to respond.
By the time the
// user responds the token may have expired. The user would
then be prompted to login again.
//
// There is no reason to store the token locally in the bot
because we can always just call
// the OAuth prompt to get the token or get a new token if
needed.
return await stepContext.beginDialog(OAUTH_PROMPT);
}
return await stepContext.endDialog();
}

async displayTokenPhase2(stepContext) {
const tokenResponse = stepContext.result;
if (tokenResponse) {
await stepContext.context.sendActivity(`Here is your token ${
tokenResponse.token }`);
}
return await stepContext.endDialog();
}
}

module.exports.MainDialog = MainDialog;

12. Open the botActivityHandler.js file and replace the content with the following
code.

javascript
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

const { DialogBot } = require('./dialogBot');

class BotActivityHandler extends DialogBot {


constructor(conversationState, userState, dialog) {
super(conversationState, userState, dialog);
this.onMembersAdded(async (context, next) =&gt; {
const membersAdded = context.activity.membersAdded;
for (let cnt = 0; cnt &lt; membersAdded.length; cnt++) {
if (membersAdded[cnt].id !==
context.activity.recipient.id) {
await context.sendActivity('Welcome to TeamsBot. Type
anything to get logged in. Type \'logout\' to sign-out.');
}
}

await next();
});
}

async handleTeamsSigninVerifyState(context, state) {


await this.dialog.run(context, this.dialogState);
}
}

module.exports.BotActivityHandler = BotActivityHandler;

13. Create a file named DialogBot.js in root folder, and add the following code to
the file.

javascript
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

const { TeamsActivityHandler } = require('botbuilder');

class DialogBot extends TeamsActivityHandler {


/**
*
* @param {ConversationState} conversationState
* @param {UserState} userState
* @param {Dialog} dialog
*/
constructor(conversationState, userState, dialog) {
super();
if (!conversationState) throw new Error('[DialogBot]: Missing
parameter. conversationState is required');
if (!userState) throw new Error('[DialogBot]: Missing parameter.
userState is required');
if (!dialog) throw new Error('[DialogBot]: Missing parameter.
dialog is required');
this.conversationState = conversationState;
this.userState = userState;
this.dialog = dialog;
this.dialogState =
this.conversationState.createProperty('DialogState');

this.onMessage(async (context, next) =&gt; {


console.log('Running dialog with Message Activity.');

// Run the Dialog with the new message Activity.


await this.dialog.run(context, this.dialogState);

await next();
});
}

/**
* Override the ActivityHandler.run() method to save state changes
after the bot logic completes.
*/
async run(context) {
await super.run(context);

// Save any state changes. The load happened during the execution
of the Dialog.
await this.conversationState.saveChanges(context, false);
await this.userState.saveChanges(context, false);
}
}

module.exports.DialogBot = DialogBot;

14. From the Visual Studio Code ribbon, select Terminal > New Terminal.

15. Execute the following command: npm install.

16. Execute the following command: npm install botbuilder-dialogs -save.


17. Run npm start to start the app.

18. In Visual Studio Code, select the F5 key to launch a Teams web client.

19. Go back to Teams. In the dialog, you could select Add for me to install the bot
as a personal bot, or you select Add to a team or Add to a chat to install the bot as a a
group/channel bot.

20. Try to sign in with the bot.

Review
In this exercise, you:

 Created a chat bot project.


 Modified code to send a proactive messages.
 Added authentication to your Teams bot.

Congratulations!

You have successfully completed Lab 04, to mark the lab as complete click End.

PreviousEnd

You might also like