Updates from: 10/21/2022 03:54:36
Service Microsoft Docs article Related commit history on GitHub Change details
platform Conversation Messages https://github.com/MicrosoftDocs/msteams-docs/commits/main/msteams-platform/bots/how-to/conversations/conversation-messages.md
Basic conversations are handled through the Bot Framework connector, a single RE
Your bot receives messages from Teams using the `Text` property and it sends single or multiple message responses to the users.
-For more information, see [User attribution for bot messages](/microsoftteams/platform/messaging-extensions/how-to/action-commands/respond-to-task-module-submit?tabs=dotnet%2Cdotnet-1&branch=pr-en-us-5926#user-attribution-for-bots-messages)
+For more information, see [user attribution for bot messages](/microsoftteams/platform/messaging-extensions/how-to/action-commands/respond-to-task-module-submit?tabs=dotnet%2Cdotnet-1&branch=pr-en-us-5926#user-attribution-for-bots-messages).
## Receive a message
-To receive a text message, use the `Text` property of the `Activity` object. In the bot's activity handler, use the turn context object's `Activity` to read a single message request.
+To receive a text message, use the `Text` property of an `Activity` object. In the bot's activity handler, use the turn context object's `Activity` to read a single message request.
The following code shows an example of receiving a message:
async def on_message_activity(self, turn_context: TurnContext):
## Send a message
-To send a text message, specify the string you want to send as the activity. In the bot's activity handler, use the turn context object's `SendActivityAsync` method to send a single message response. Use the object's `SendActivitiesAsync` method to send multiple responses at once.
+To send a text message, specify the string you want to send as an activity. In the bot's activity handler, use the turn context object's `SendActivityAsync` method to send a single message response. Use the object's `SendActivitiesAsync` method to send multiple responses.
The following code shows an example of sending a message when a user is added to a conversation:
async def on_members_added_activity(
> [!NOTE] >
->* Message splitting occurs when a text message and an attachment are sent in the same activity payload. This activity is split into separate activities by Microsoft Teams, one with just a text message and the other with an attachment. As the activity is split, you do not receive the message ID in response, which is used to [update or delete](~/bots/how-to/update-and-delete-bot-messages.md) the message proactively. It is recommended to send separate activities instead of depending on message splitting.
->* Messages sent can be localized to provide personalization. For more information, see [Localize your app](../../../concepts/build-and-test/apps-localization.md).
+>* Message splitting occurs when a text message and an attachment are sent in the same activity payload. Teams splits this activity into two separate activities, one with a text message and the other with an attachment. As the activity is split, you do not receive the message ID in response, which is used to [update or delete](~/bots/how-to/update-and-delete-bot-messages.md) the message proactively. It is recommended to send separate activities instead of depending on message splitting.
+>* Messages sent can be localized to provide personalization. For more information, see [localize your app](../../../concepts/build-and-test/apps-localization.md).
Messages sent between users and bots include internal channel data within the message. This data allows the bot to communicate properly on that channel. The Bot Builder SDK allows you to modify the message structure. ## Send suggested actions
-Suggested actions enable your bot to present buttons that the user can select to provide input. Suggested actions enhance user experience by enabling the user to answer a question or make a choice with selection of a button, rather than typing a response with a keyboard.
-The buttons remain visible and accessible to the user in the rich cards even after user makes a selection whereas for suggested actions, buttons aren't available. This prevents the user from selection of stale buttons within a conversation.
+The suggested actions enable your bot to present buttons that the user can select to provide input. Suggested actions enhance user experience by enabling the user to answer a question or make a choice with selection of a button, rather than typing a response with a keyboard.
+When the user selects a button, it remains visible and accessible in the rich cards, but not for the suggested actions. This prevents the user from selection of stale buttons within a conversation.
-To add suggested actions to a message, set the `suggestedActions` property of the [Activity](/azure/bot-service/rest-api/bot-framework-rest-connector-api-reference) object to specify the list of [CardAction](/azure/bot-service/rest-api/bot-framework-rest-connector-api-reference) objects that represent the buttons to be presented to the user. For more information, see [`SugestedActions`](/dotnet/api/microsoft.bot.builder.messagefactory.suggestedactions)
+To add suggested actions to a message, set the `suggestedActions` property of an [activity](/azure/bot-service/rest-api/bot-framework-rest-connector-api-reference) object to specify the list of [card action](/azure/bot-service/rest-api/bot-framework-rest-connector-api-reference) objects that represent the buttons to be presented to the user. For more information, see [`sugestedActions`](/dotnet/api/microsoft.bot.builder.messagefactory.suggestedactions).
The following is an example for implementation and experience of suggested actions:
The following is an example for implementation and experience of suggested actio
} ```
+The following illustrates an example of suggested actions:
+ :::image type="content" source="~/assets/images/Cards/suggested-actions.png" alt-text="Bot suggested actions" border="true"::: > [!NOTE] > > * `SuggestedActions` are only supported for one-on-one chat bots and text based messages and not for Adaptive Cards or attachments.
-> * Currently `imBack` is the only supported action type and Teams display up to three suggested actions.
+> * `imBack` is the only supported action type and Teams display up to three suggested actions.
## Teams channel data
-The `channelData` object contains Teams-specific information and is a definitive source for team and channel IDs. Optionally, you can cache and use these IDs as keys for local storage. The `TeamsActivityHandler` in the SDK pulls out important information from the `channelData` object to make it easily accessible. However, you can always access the original data from the `turnContext` object.
+The `channelData` object contains Teams-specific information and is a definitive source for team and channel IDs. Optionally, you can cache and use these IDs as keys for local storage. The `TeamsActivityHandler` in the SDK pulls out important information from the `channelData` object to make it accessible. However, you can always access the original data from the `turnContext` object.
The `channelData` object isn't included in messages in personal conversations, as these take place outside of a channel.
Messages received from or sent to your bot can include different types of messag
| Format | From user to bot | From bot to user | Notes | |--|||--| | Rich text | ✔️ | ✔️ | Your bot can send rich text, pictures, and cards. Users can send rich text and pictures to your bot. |
-| Pictures | ✔️ | ✔️ | Maximum 1024 × 1024 pixels and 1 MB in PNG, JPEG, or GIF format. Animated GIF isn't supported. |
-| Cards | ❌ | ✔️ | See the [Teams card reference](~/task-modules-and-cards/cards/cards-reference.md) for supported cards. |
+| Pictures | ✔️ | ✔️ | Maximum 1024 × 1024 pixels and 1 MB in PNG, JPEG, or GIF format. Doesn't support the animated GIF. |
+| Cards | ❌ | ✔️ | See [Teams card reference](~/task-modules-and-cards/cards/cards-reference.md) for supported cards. |
| Emojis | ✔️ | ✔️ | Teams currently supports emojis through UTF-16, such as U+1F600 for grinning face. |
-## Notifications to your message
+### Picture messages
+
+To enhance your message, you can include pictures as attachments to that message. For more information on attachments, see [add media attachments to messages](/azure/bot-service/dotnet/bot-builder-dotnet-add-media-attachments).
+
+Pictures can be at most 1024 × 1024 pixels and 1 MB in PNG, JPEG, or GIF format. Animated GIF isn't supported.
+
+Specify the height and width of each image by using XML. In Markdown, the image size defaults to 256×256. For example:
+
+* Use: `<img src="http://aka.ms/Fo983c" alt="Duck on a rock" height="150" width="223"></img>`.
+* Don't use: `![Duck on a rock](http://aka.ms/Fo983c)`.
+
+A conversational bot can include Adaptive Cards that simplify business workflows. Adaptive Cards offer rich customizable text, speech, images, buttons, and input fields.
+
+### Adaptive Cards
+
+Adaptive Cards can be authored in a bot and shown in multiple apps such as Teams, your website, and so on. For more information, see [Adaptive Cards](~/task-modules-and-cards/cards/cards-reference.md#adaptive-card).
+
+The following code shows an example of sending a simple Adaptive Card:
+
+```json
+{
+ "type": "AdaptiveCard",
+ "$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
+ "version": "1.5",
+ "body": [
+ {
+ "items": [
+ {
+ "size": "large",
+ "text": " Simple Adaptivecard Example with a Textbox",
+ "type": "TextBlock",
+ "weight": "bolder",
+ "wrap": true
+ },
+ ],
+ "spacing": "extraLarge",
+ "type": "Container",
+ "verticalContentAlignment": "center"
+ }
+ ]
+}
+```
+
+#### Form completion feedback
+
+You can build form completion feedback using an Adaptive Card. Form completion message appears in Adaptive Cards while sending a response to the bot. The message can be of two types, error or success:
+
+* **Error**: When a response sent to the bot is unsuccessful, **Something went wrong, Try again** message appears.
+
+ :::image type="content" source="../../../assets/images/Cards/error-message.png" alt-text="Error message"border="true":::
+
+* **Success**: When a response sent to the bot is successful, **Your response was sent to the app** message appears.
+
+ :::image type="content" source="../../../assets/images/Cards/success.PNG" alt-text="Success message"border="true":::
+
+ You can select **Close** or switch chat to dismiss the message.
+
+ If you don't want to display the success message, set the attribute `hide` to `true` in the `msTeams` `feedback` property. Following is an example:
+
+ ```json
+ "content": {
+ "type": "AdaptiveCard",
+ "title": "Card with hidden footer messages",
+ "version": "1.0",
+ "actions": [
+ {
+ "type": "Action.Submit",
+ "title": "Submit",
+ "msTeams": {
+ "feedback": {
+ "hide": true
+ }
+ }
+ }
+ ]
+ }
+ ```
+
+For more information on cards and cards in bots, see [cards documentation](~/task-modules-and-cards/what-are-cards.md).
+
+## Add notifications to your message
+
+There are two ways to send a notification from your application:
+
+* By setting the `Notification.Alert` property on bot message.
+* By sending an activity feed notification using the Graph API.
-You can also add notifications to your message using the `Notification.Alert` property. Notifications alert users about new tasks, mentions, and comments. These alerts are related to what users are working on or what they must look at by inserting a notice into their activity feed. For notifications to trigger from your bot message, set the `TeamsChannelData` objects `Notification.Alert` property to *true*. Whether or not a notification is raised depends on the individual user's Teams settings and you can't override these settings. The notification type is either a banner or both a banner and an email.
+You can add notifications to your message using the `Notification.Alert` property. Notifications alert users to an event in your application such as new tasks, mentions, or comments. These alerts are related to what users are working on or what they must look at by inserting a notice into their activity feed. For notifications to trigger from your bot message, set the `TeamsChannelData` objects `Notification.Alert` property to *true*. If a notification is raised depends on the individual user's Teams settings, and you can't override these settings.
+
+If you want to generate an arbitrary notification without sending a message to the user, then you can use the Graph API. For more information, see [how to send activity feed notifications using Graph API](/graph/teams-send-activityfeednotifications) along with the [best practices](/graph/teams-activity-feed-notifications-best-practices).
> [!NOTE] > The **Summary** field displays any text from the user as a notification message in the feed.
async def on_message_activity(self, turn_context: TurnContext):
-To enhance your message, you can include pictures as attachments to that message.
-
-## Picture messages
-
-Pictures are sent by adding attachments to a message. For more information on attachments, see [add media attachments to messages](/azure/bot-service/dotnet/bot-builder-dotnet-add-media-attachments).
-
-Pictures can be at most 1024×1024 MB and 1 MB in PNG, JPEG, or GIF format. Animated GIF isn't supported.
-
-Specify the height and width of each image by using XML. In markdown, the image size defaults to 256×256. For example:
-
-* Use: `<img src="http://aka.ms/Fo983c" alt="Duck on a rock" height="150" width="223"></img>`.
-* Don't use: `![Duck on a rock](http://aka.ms/Fo983c)`.
-
-A conversational bot can include Adaptive Cards that simplify business workflows. Adaptive Cards offer rich customizable text, speech, images, buttons, and input fields.
-
-## Adaptive Cards
-
-Adaptive Cards can be authored in a bot and shown in multiple apps such as Teams, your website, and so on. For more information, see [Adaptive Cards](~/task-modules-and-cards/cards/cards-reference.md#adaptive-card).
-
-The following code shows an example of sending a simple Adaptive Card:
-
-```json
-{
- "type": "AdaptiveCard",
- "$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
- "version": "1.5",
- "body": [
- {
- "items": [
- {
- "size": "large",
- "text": " Simple Adaptivecard Example with a Textbox",
- "type": "TextBlock",
- "weight": "bolder",
- "wrap": true
- },
- ],
- "spacing": "extraLarge",
- "type": "Container",
- "verticalContentAlignment": "center"
- }
- ]
-}
-```
-
-### Form completion feedback
-
-Form completion message appears in Adaptive Cards while sending a response to the bot. The message can be of two types, error or success:
-
-* **Error**: When a response sent to the bot is unsuccessful, **Something went wrong, Try again** message appears.
-
- :::image type="content" source="../../../assets/images/Cards/error-message.png" alt-text="Error message"border="true":::
-
-* **Success**: When a response sent to the bot is successful, **Your response was sent to the app** message appears.
-
- :::image type="content" source="../../../assets/images/Cards/success.PNG" alt-text="Success message"border="true":::
-
- You can select **Close** or switch chat to dismiss the message.
-
- If you don't want to display the success message, set the attribute `hide` to `true` in the `msTeams` `feedback` property. Following is an example:
-
- ```json
- "content": {
- "type": "AdaptiveCard",
- "title": "Card with hidden footer messages",
- "version": "1.0",
- "actions": [
- {
- "type": "Action.Submit",
- "title": "Submit",
- "msTeams": {
- "feedback": {
- "hide": true
- }
- }
- }
- ]
- }
- ```
-
-For more information on cards and cards in bots, see [cards documentation](~/task-modules-and-cards/what-are-cards.md).
- ## Status codes from bot conversational APIs Ensure to handle these errors appropriately in your Teams app. The following table lists the error codes and the descriptions under which the errors are generated:
Ensure to handle these errors appropriately in your Teams app. The following tab
### Status codes retry guidance
-The general retry guidance for each status code is listed in the following table. Bot should avoid retrying on status codes that are not specified in the following table:
+The general retry guidance for each status code is listed in the following table, bot must avoid retrying status codes that aren't specified:
|Status code | Retry strategy | |-|--| | 412 | Retry using exponential backoff. |
-| 429 | Retry using `Retry-After` header to determine wait time in seconds and in between requests, if available . Otherwise, retry using exponential backoff with thread ID, if possible. |
+| 429 | Retry using `Retry-After` header to determine wait time in seconds and in between requests, if available. Otherwise, retry using exponential backoff with thread ID, if possible. |
| 502 | Retry using exponential backoff. | | 503 | Retry using exponential backoff. | | 504 | Retry using exponential backoff. |
platform Media Capabilities https://github.com/MicrosoftDocs/msteams-docs/commits/main/msteams-platform/concepts/device-capabilities/media-capabilities.md
Update your Teams app [manifest.json](../../resources/schem#
The [selectMedia](/javascript/api/@microsoft/teams-js/media#@microsoft-teams-js-media-selectmedia), [getMedia](/javascript/api/@microsoft/teams-js/media.media#@microsoft-teams-js-media-media-getmedia), and [viewImages](/javascript/api/@microsoft/teams-js/media#@microsoft-teams-js-media-viewimages) APIs enable you to use native media capabilities as follows: * Use the native **microphone** to allow users to **record audio** (record 10 minutes of conversation) from the device.
-* Use native **camera control** to allow users to **capture and attach images** and **capture videos** (record upto 5 minutes of video) on the go.
+* Use native **camera control** to allow users to **capture and attach images** and **capture videos** (record up to five minutes of video) on the go.
* Use native **gallery support** to allow users to **select device images** as attachments. * Use native **image viewer control** to **preview multiple images** at one time. * Support **large image transfer** (from 1 MB to 50 MB) through the SDK bridge.
The [selectMedia](/javascript/api/@microsoft/teams-js/media#@microsoft-teams-js-
> [!IMPORTANT] > > * The `selectMedia`, `getMedia`, and `viewImages` APIs can be invoked from multiple Teams surfaces, such as task modules, tabs, and personal apps. For more information, see [Entry points for Teams apps](../extensibility-points.md).</br>
-> * `selectMedia` API supports both camera and microphone capabilities through different input configurations.
+> * The `selectMedia` API supports both camera and microphone capabilities through different input configurations.
> * The `selectMedia` API for accessing microphone capability supports for mobile clients only.
+> * The maximum count of images uploaded is determined by [`maxMediaCount`](/javascript/api/@microsoft/teams-js/media.mediainputs#@microsoft-teams-js-media-mediainputs-maxmediacount) and also by the total size of array returned by the `selectMedia` API. Ensure that the array size doesn't exceed 4 MB, if the array size exceeds 4 MB, the API generates an error code 10000 that is SIZE_EXCEEDED error.
The following table lists set of APIs to enable your device's media capabilities:
platform Add Single Sign On https://github.com/MicrosoftDocs/msteams-docs/commits/main/msteams-platform/toolkit/add-single-sign-on.md
Teams Toolkit helps you to add SSO to the following Teams capabilities:
* Bot * Notification bot: restify server * Command bot
+* Message extension
### Add SSO using Visual Studio Code
-The following steps help you to add SSO using Teams Toolkit in Visual Studio Code
+To add SSO using Teams Toolkit in Visual Studio Code, follow these steps:
1. Open **Microsoft Visual Studio Code**.
-2. Select Teams Toolkit :::image type="content" source="~/assets/images/teams-toolkit-v2/teams-toolkit-sidebar-icon.png" alt-text="sso add sidebar"::: from left navigation bar.
+2. Select Teams Toolkit :::image type="content" source="~/assets/images/teams-toolkit-v2/teams-toolkit-sidebar-icon.png" alt-text="Screenshot is an example of the Teams Toolkit option in Visual Studio Code."::: from left navigation bar.
3. Select **Add features** under **DEVELOPMENT**.
- :::image type="content" source="../assets/images/teams-toolkit-v2/add-sso/sso-add features.png" alt-text="sso add features":::
+ :::image type="content" source="../assets/images/teams-toolkit-v2/add-sso/sso-add features.png" alt-text="Screenshot shows the Add features option under the Development option in the Visual Studio Code.":::
- * You can also open command palette and select **Teams: Add features**
+ * You can also open command palette and select **Teams: Add features**.
4. Select **Single Sign-On**.
- :::image type="content" source="../assets/images/teams-toolkit-v2/add-sso/sso-select features.png" alt-text="sso select":::
+ :::image type="content" source="../assets/images/teams-toolkit-v2/add-sso/sso-select features.png" alt-text="Screenshot shows the Single Sign-on feature highlighted in red in the Visual Studio Code.":::
### Add SSO using TeamsFx CLI
-You can run `teamsfx add sso` command in your **project root directory**
+You can run `teamsfx add sso` command in your **project root directory**.
-> [!Note]
+> [!NOTE]
> The feature enables SSO for all existing applicable capabilities. Follow the same steps to enable SSO if you add capability later to the project. ## Customize your project using Teams Toolkit The following table lists the changes Teams Toolkit makes to your project:
- |**Type**|**File**|**Purpose**|
- |--|--|--|
- |Create|`aad.template.json` under `template/appPackage`|Azure AD application manifest represents your Azure AD app. `template/appPackage` helps to register an Azure AD app during local debug or provision stage.|
- |Modify|`manifest.template.json` under `template/appPackage`|A `webApplicationInfo` object is added into your Teams app manifest template. Teams requires this field to enable SSO. The change is in effect when you trigger local debug or provision.|
- |Create|`auth/tab`|Reference code, auth redirect pages, and `README.md` files are generated in this path for a tab project.|
- |Create|`auth/bot`|Reference code, auth redirect pages, and `README.md` files are generated in this path for a bot project.|
+| **Type** | **File** | **Purpose** |
+| -- | - | -- |
+| Create | `aad.template.json` under `template/appPackage` | Azure AD application manifest represents your Azure AD app. `template/appPackage` helps to register an Azure AD app during local debug or provision stage. |
+| Modify | `manifest.template.json` under `template/appPackage` | A `webApplicationInfo` object is added into your Teams app manifest template. Teams requires this field to enable SSO. The change is in effect when you trigger local debug or provision. |
+| Create | `auth/tab` | Reference code, auth redirect pages, and `README.md` files are generated in this path for a tab project. |
+| Create | `auth/bot` | Reference code, auth redirect pages, and `README.md` files are generated in this path for a bot project. |
-> [!Note]
+> [!NOTE]
> By adding SSO, Teams Toolkit doesn't change anything in the cloud until you trigger local debug. Update your code to ensure that SSO is working in the project. ## Update your application to use SSO
-The following steps help you to enable SSO in your application:
+To enable SSO in your application, follow these steps:
> [!NOTE] > These changes are based on the templates we scaffold. + <br> <br><details> <summary><b>Tab project </b></summary>
-1. Copy `auth-start.html` and `auth-end.htm`** in `auth/public` folder to `tabs/public/`. Teams Toolkit registers these two endpoints in Azure AD for Azure AD's redirect flow.
+1. Copy `auth-start.html` and `auth-end.htm`\*\* in `auth/public` folder to `tabs/public/`. Teams Toolkit registers these two endpoints in Azure AD for Azure AD's redirect flow.
2. Copy `sso` folder under `auth/tab` to `tabs/src/sso/`.
- * `InitTeamsFx`: The file implements a function that initializes TeamsFx SDK and opens `GetUserProfile` component after SDK is initialized
+ * `InitTeamsFx`: The file implements a function that initializes TeamsFx SDK and opens `GetUserProfile` component after SDK is initialized.
- * `GetUserProfile`: The file implements a function that calls Microsoft Graph API to get user info
+ * `GetUserProfile`: The file implements a function that calls Microsoft Graph API to get user info.
3. Execute `npm install @microsoft/teamsfx-react` under `tabs/`. 4. Add the following lines to `tabs/src/components/sample/Welcome.tsx` to import `InitTeamsFx`:
- ```Bash
+ ```Bash
- import { InitTeamsFx } from "../../sso/InitTeamsFx";
+ import { InitTeamsFx } from "../../sso/InitTeamsFx";
- ```
+ ```
5. Replace the following line:
The following steps help you to enable SSO in your application:
1. Move the `auth/bot/public` folder to `bot/src`. This folder contains HTML pages that the bot application hosts. When single sign-on flow is initiated with Azure AD, it redirects the user to the HTML pages. 1. Modify your `bot/src/index` to add the appropriate `restify` routes to HTML pages.
- ```ts
- const path = require("path");
+ ```ts
+ const path = require("path");
- server.get(
- "/auth-*.html",
- restify.plugins.serveStatic({
- directory: path.join(__dirname, "public"),
- })
- );
- ```
+ server.get(
+ "/auth-*.html",
+ restify.plugins.serveStatic({
+ directory: path.join(__dirname, "public"),
+ })
+ );
+ ```
#### Update your app SSO command handler `ProfileSsoCommandHandler` uses an Azure AD token to call Microsoft Graph. This token is obtained by using the logged-in Teams user token. The flow is brought together in a dialog that displays a consent dialog if necessary. 1. Move `profileSsoCommandHandler` file under `auth/bot/sso` folder to `bot/src`. `ProfileSsoCommandHandler` class is an SSO command handler to get user info with SSO token, follow this method and create your own SSO command handler.
-1. Open `package.json` file and ensure that teamsfx SDK version >= 1.2.0
-1. Execute the `npm install isomorphic-fetch --save` command in `bot` folder.
-1. For ts script, execute the `npm install copyfiles --save-dev` command in `bot` folder and replace following lines in `package.json`:
+1. Open `package.json` file and ensure that teamsfx SDK version >= 1.2.0.
+1. Execute the `npm install isomorphic-fetch --save` command in the `bot` folder.
+1. For ts script, execute the `npm install copyfiles --save-dev` command in the `bot` folder and replace following lines in `package.json`:
- ```json
- "build": "tsc --build && shx cp -r ./src/adaptiveCards ./lib/src",
- ```
+ ```json
+ "build": "tsc --build && shx cp -r ./src/adaptiveCards ./lib/src",
+ ```
- with
+ with
- ```json
- "build": "tsc --build && shx cp -r ./src/adaptiveCards ./lib/src && copyfiles src/public/*.html lib/",
- ```
+ ```json
+ "build": "tsc --build && shx cp -r ./src/adaptiveCards ./lib/src && copyfiles src/public/*.html lib/",
+ ```
- This copies the HTML pages used for auth redirect when building the bot project.
+ This copies the HTML pages used for auth redirect when building the bot project.
1. To make SSO consent flow work, replace the following code in `bot/src/index` file:
- ```ts
- server.post("/api/messages", async (req, res) => {
- await commandBot.requestHandler(req, res);
- });
- ```
-
- with
-
- ```ts
- server.post("/api/messages", async (req, res) => {
- await commandBot.requestHandler(req, res).catch((err) => {
- // Error message including "412" means it is waiting for user's consent, which is a normal process of SSO, sholdn't throw this error.
- if (!err.message.includes("412")) {
- throw err;
- }
- });
- });
- ```
+ ```ts
+ server.post("/api/messages", async (req, res) => {
+ await commandBot.requestHandler(req, res);
+ });
+ ```
+
+ with
+
+ ```ts
+ server.post("/api/messages", async (req, res) => {
+ await commandBot.requestHandler(req, res).catch((err) => {
+ // Error message including "412" means it is waiting for user's consent, which is a normal process of SSO, sholdn't throw this error.
+ if (!err.message.includes("412")) {
+ throw err;
+ }
+ });
+ });
+ ```
1. Replace the options for `ConversationBot` instance in `bot/src/internal/initialize` to add the SSO config and SSO command handler:
- ```ts
- export const commandBot = new ConversationBot({
- ...
- command: {
- enabled: true,
- commands: [new HelloWorldCommandHandler()],
- },
- });
- ```
-
- with
-
- ```ts
- import { ProfileSsoCommandHandler } from "../profileSsoCommandHandler";
-
- export const commandBot = new ConversationBot({
- ...
- // To learn more about ssoConfig, please refer teamsfx sdk document: https://docs.microsoft.com/microsoftteams/platform/toolkit/teamsfx-sdk
- ssoConfig: {
- aad :{
- scopes:["User.Read"],
- },
- },
- command: {
- enabled: true,
- commands: [new HelloWorldCommandHandler() ],
- ssoCommands: [new ProfileSsoCommandHandler()],
- },
- });
- ```
+ ```ts
+ export const commandBot = new ConversationBot({
+ ...
+ command: {
+ enabled: true,
+ commands: [new HelloWorldCommandHandler()],
+ },
+ });
+ ```
+
+ with
+
+ ```ts
+ import { ProfileSsoCommandHandler } from "../profileSsoCommandHandler";
+
+ export const commandBot = new ConversationBot({
+ ...
+ // To learn more about ssoConfig, please refer teamsfx sdk document: https://docs.microsoft.com/microsoftteams/platform/toolkit/teamsfx-sdk
+ ssoConfig: {
+ aad :{
+ scopes:["User.Read"],
+ },
+ },
+ command: {
+ enabled: true,
+ commands: [new HelloWorldCommandHandler() ],
+ ssoCommands: [new ProfileSsoCommandHandler()],
+ },
+ });
+ ```
1. Register your command in the Teams app manifest. Open `templates/appPackage/manifest.template.json`, and add following lines under `commands` in `commandLists` of your bot:
- ```json
- {
- "title": "profile",
- "description": "Show user profile using Single Sign On feature"
- }
- ```
+ ```json
+ {
+ "title": "profile",
+ "description": "Show user profile using Single Sign On feature"
+ }
+ ```
#### Add a new SSO command to the bot (Optional)
After successfully adding SSO in your project, you can add a new SSO command.
1. Create a new file such as `photoSsoCommandHandler.ts` or `photoSsoCommandHandler.js` in `bot/src/` and add your own SSO command handler to call Graph API:
- ```TypeScript
- // for TypeScript:
- import { Activity, TurnContext, ActivityTypes } from "botbuilder";
- import "isomorphic-fetch";
- import {
- CommandMessage,
- TriggerPatterns,
- TeamsFx,
- createMicrosoftGraphClient,
- TeamsFxBotSsoCommandHandler,
- TeamsBotSsoPromptTokenResponse,
- } from "@microsoft/teamsfx";
-
- export class PhotoSsoCommandHandler implements TeamsFxBotSsoCommandHandler {
- triggerPatterns: TriggerPatterns = "photo";
-
- async handleCommandReceived(
- context: TurnContext,
- message: CommandMessage,
- tokenResponse: TeamsBotSsoPromptTokenResponse,
- ): Promise<string | Partial<Activity> | void> {
- await context.sendActivity("Retrieving user information from Microsoft Graph ...");
-
- const teamsfx = new TeamsFx().setSsoToken(tokenResponse.ssoToken);
-
- const graphClient = createMicrosoftGraphClient(teamsfx, ["User.Read"]);
-
- let photoUrl = "";
- try {
- const photo = await graphClient.api("/me/photo/$value").get();
- const arrayBuffer = await photo.arrayBuffer();
- const buffer=Buffer.from(arrayBuffer, 'binary');
- photoUrl = "data:image/png;base64," + buffer.toString("base64");
- } catch {
- // Could not fetch photo from user's profile, return empty string as placeholder.
- }
- if (photoUrl) {
- const photoMessage: Partial<Activity> = {
- type: ActivityTypes.Message,
- text: 'This is your photo:',
- attachments: [
- {
- name: 'photo.png',
- contentType: 'image/png',
- contentUrl: photoUrl
- }
- ]
- };
- return photoMessage;
- } else {
- return "Could not retrieve your photo from Microsoft Graph. Please make sure you have uploaded your photo.";
- }
- }
- }
- ```
+ ```TypeScript
+ // for TypeScript:
+ import { Activity, TurnContext, ActivityTypes } from "botbuilder";
+ import "isomorphic-fetch";
+ import {
+ CommandMessage,
+ TriggerPatterns,
+ TeamsFx,
+ createMicrosoftGraphClient,
+ TeamsFxBotSsoCommandHandler,
+ TeamsBotSsoPromptTokenResponse,
+ } from "@microsoft/teamsfx";
+
+ export class PhotoSsoCommandHandler implements TeamsFxBotSsoCommandHandler {
+ triggerPatterns: TriggerPatterns = "photo";
+
+ async handleCommandReceived(
+ context: TurnContext,
+ message: CommandMessage,
+ tokenResponse: TeamsBotSsoPromptTokenResponse,
+ ): Promise<string | Partial<Activity> | void> {
+ await context.sendActivity("Retrieving user information from Microsoft Graph ...");
+
+ const teamsfx = new TeamsFx().setSsoToken(tokenResponse.ssoToken);
+
+ const graphClient = createMicrosoftGraphClient(teamsfx, ["User.Read"]);
+
+ let photoUrl = "";
+ try {
+ const photo = await graphClient.api("/me/photo/$value").get();
+ const arrayBuffer = await photo.arrayBuffer();
+ const buffer=Buffer.from(arrayBuffer, 'binary');
+ photoUrl = "data:image/png;base64," + buffer.toString("base64");
+ } catch {
+ // Could not fetch photo from user's profile, return empty string as placeholder.
+ }
+ if (photoUrl) {
+ const photoMessage: Partial<Activity> = {
+ type: ActivityTypes.Message,
+ text: 'This is your photo:',
+ attachments: [
+ {
+ name: 'photo.png',
+ contentType: 'image/png',
+ contentUrl: photoUrl
+ }
+ ]
+ };
+ return photoMessage;
+ } else {
+ return "Could not retrieve your photo from Microsoft Graph. Please make sure you have uploaded your photo.";
+ }
+ }
+ }
+ ```
+
+ ```javascript
+ // for JavaScript:
+ const { ActivityTypes } = require("botbuilder");
+ require("isomorphic-fetch");
+ const {
+ createMicrosoftGraphClient,
+ TeamsFx,
+ } = require("@microsoft/teamsfx");
+
+ class PhotoSsoCommandHandler {
+ triggerPatterns = "photo";
+
+ async handleCommandReceived(context, message, tokenResponse) {
+ await context.sendActivity(
+ "Retrieving user information from Microsoft Graph ..."
+ );
+
+ const teamsfx = new TeamsFx().setSsoToken(tokenResponse.ssoToken);
+
+ const graphClient = createMicrosoftGraphClient(teamsfx, ["User.Read"]);
+
+ let photoUrl = "";
+ try {
+ const photo = await graphClient.api("/me/photo/$value").get();
+ const arrayBuffer = await photo.arrayBuffer();
+ const buffer = Buffer.from(arrayBuffer, "binary");
+ photoUrl = "data:image/png;base64," + buffer.toString("base64");
+ } catch {
+ // Could not fetch photo from user's profile, return empty string as placeholder.
+ }
+ if (photoUrl) {
+ const photoMessage = {
+ type: ActivityTypes.Message,
+ text: "This is your photo:",
+ attachments: [
+ {
+ name: "photo.png",
+ contentType: "image/png",
+ contentUrl: photoUrl,
+ },
+ ],
+ };
+ return photoMessage;
+ } else {
+ return "Could not retrieve your photo from Microsoft Graph. Please make sure you have uploaded your photo.";
+ }
+ }
+ }
+
+ module.exports = {
+ PhotoSsoCommandHandler,
+ };
+ ```
- ```javascript
- // for JavaScript:
- const { ActivityTypes } = require("botbuilder");
- require("isomorphic-fetch");
- const { createMicrosoftGraphClient, TeamsFx } = require("@microsoft/teamsfx");
-
- class PhotoSsoCommandHandler {
- triggerPatterns = "photo";
-
- async handleCommandReceived(context, message, tokenResponse) {
- await context.sendActivity("Retrieving user information from Microsoft Graph ...");
-
- const teamsfx = new TeamsFx().setSsoToken(tokenResponse.ssoToken);
-
- const graphClient = createMicrosoftGraphClient(teamsfx, ["User.Read"]);
-
- let photoUrl = "";
- try {
- const photo = await graphClient.api("/me/photo/$value").get();
- const arrayBuffer = await photo.arrayBuffer();
- const buffer=Buffer.from(arrayBuffer, 'binary');
- photoUrl = "data:image/png;base64," + buffer.toString("base64");
- } catch {
- // Could not fetch photo from user's profile, return empty string as placeholder.
- }
- if (photoUrl) {
- const photoMessage = {
- type: ActivityTypes.Message,
- text: 'This is your photo:',
- attachments: [
- {
- name: 'photo.png',
- contentType: 'image/png',
- contentUrl: photoUrl
- }
- ]
- };
- return photoMessage;
- } else {
- return "Could not retrieve your photo from Microsoft Graph. Please make sure you have uploaded your photo.";
- }
- }
- }
+1. Add `PhotoSsoCommandHandler` instance to `ssoCommands` array in `bot/src/internal/initialize.ts`:
- module.exports = {
- PhotoSsoCommandHandler,
- };
+ ```ts
+ // for TypeScript:
+ import { PhotoSsoCommandHandler } from "../photoSsoCommandHandler";
+
+ export const commandBot = new ConversationBot({
+ ...
+ command: {
+ ...
+ ssoCommands: [new ProfileSsoCommandHandler(), new PhotoSsoCommandHandler()],
+ },
+ });
+ ```
+
+ ```javascript
+ // for JavaScript:
+ ...
+ const { PhotoSsoCommandHandler } = require("../photoSsoCommandHandler");
+
+ const commandBot = new ConversationBot({
+ ...
+ command: {
+ ...
+ ssoCommands: [new ProfileSsoCommandHandler(), new PhotoSsoCommandHandler()]
+ },
+ });
+ ...
+
+ ```
- ```
+1. Register your command in the Teams app manifest. Open `templates/appPackage/manifest.template.json`, and add following lines under `commands` in `commandLists` of your bot:
-1. Add `PhotoSsoCommandHandler` instance to `ssoCommands` array in `bot/src/internal/initialize.ts`:
+ ```JSON
+
+ {
+ "title": "photo",
+ "description": "Show user photo using Single Sign On feature"
+ }
+
+ ```
+
+</details>
+
+<details>
+<summary><b>Message extension project
+</b></summary>
+
+The sample business logic provides a handler `TeamsBot` extends TeamsActivityHandler and override `handleTeamsMessagingExtensionQuery`.
+
+You can update the query logic in the `handleMessageExtensionQueryWithToken` with token, which is obtained by using the logged-in Teams user token.
+
+To make this work in your application:
+
+1. Move the `auth/bot/public` folder to `bot`. This folder contains HTML pages that the bot application hosts. When single sign-on flows are initiated with Azure AD, Azure AD will redirect the user to these pages.
+
+1. Modify your `bot/index` to add the appropriate `restify` routes to these pages.
```ts
- // for TypeScript:
- import { PhotoSsoCommandHandler } from "../photoSsoCommandHandler";
-
- export const commandBot = new ConversationBot({
- ...
- command: {
- ...
- ssoCommands: [new ProfileSsoCommandHandler(), new PhotoSsoCommandHandler()],
- },
- });
+ const path = require("path");
+
+ server.get(
+ "/auth-*.html",
+ restify.plugins.serveStatic({
+ directory: path.join(__dirname, "public"),
+ })
+ );
```
- ```javascript
- // for JavaScript:
- ...
- const { PhotoSsoCommandHandler } = require("../photoSsoCommandHandler");
+1. Override `handleTeamsMessagingExtensionQuery` interface under `bot/teamsBot`. You can follow the sample code in the `handleMessageExtensionQueryWithToken` to do your own query logic.
- const commandBot = new ConversationBot({
- ...
- command: {
- ...
- ssoCommands: [new ProfileSsoCommandHandler(), new PhotoSsoCommandHandler()]
- },
- });
- ...
+1. Open `bot/package.json`, ensure that `@microsoft/teamsfx` version >= 1.2.0
- ```
+1. Install `isomorphic-fetch` npm packages in your bot project.
-1. Register your command in the Teams app manifest. Open `templates/appPackage/manifest.template.json`, and add following lines under `commands` in `commandLists` of your bot:
+1. (For ts only) Install `copyfiles` npm packages in your bot project, add or update the `build` script in `bot/package.json` as follows:
+
+ ```json
+ "build": "tsc --build && copyfiles ./public/*.html lib/",
+ ```
- ```JSON
+ By doing this, the HTML pages used for auth redirect will be copied when building this bot project.
- {
- "title": "photo",
- "description": "Show user photo using Single Sign On feature"
- }
+1. Update `templates/appPackage/aad.template.json` your scopes which used in `handleMessageExtensionQueryWithToken`.
+ ```json
+ "requiredResourceAccess": [
+ {
+ "resourceAppId": "Microsoft Graph",
+ "resourceAccess": [
+ {
+ "id": "User.Read",
+ "type": "Scope"
+ }
+ ]
+ }
+ ]
``` </details>+ <br> ## Debug your application
To view your Azure AD application in Azure portal, see [View Azure AD applicatio
## SSO authentication concepts
-The following concepts help you for SSO authentication:
+The following concepts help you with SSO authentication:
### Working of SSO in Teams Single sign-on (SSO) authentication in Microsoft Azure Active Directory (Azure AD) silently refreshes the authentication token to minimize the number of times users need to enter their sign-in credentials. If users agree to use your app, they don't have to provide consent again on another device as they're signed in automatically.
-Teams tabs and bots have similar flow for SSO support, for more information, see:
+Teams tabs and bots have similar flow for SSO support. For more information, see:
1. [Single sign-on (SSO) authentication in Tabs](../tabs/how-to/authentication/tab-sso-overview.md)
-2. [Single sign-on (SSO) authentication in Bots](../bots/how-to/authentication/auth-aad-sso-bots.md)
+1. [Single sign-on (SSO) authentication in Bots](../bots/how-to/authentication/auth-aad-sso-bots.md)
### Simplified SSO with TeamsFx
TeamsFx helps to reduce the developer tasks by using SSO and accessing cloud res
With TeamsFx SDK, you can write user authentication code in a simplified way using Credentials: 1. User identity in browser environment: `TeamsUserCredential` represents Teams current user's identity.
-2. User identity in Node.js environment: `OnBehalfOfUserCredential` uses On-Behalf-Of flow and SSO token.
-3. Application Identity in Node.js environment: `AppCredential` represents the application identity.
+1. User identity in Node.js environment: `OnBehalfOfUserCredential` uses On-Behalf-Of flow and SSO token.
+1. Application Identity in Node.js environment: `AppCredential` represents the application identity.
For more information about TeamsFx SDK, see:
For more information about TeamsFx SDK, see:
## See also
-* [Prerequisites for creating your Teams app](tools-prerequisites.md)
+[Prerequisites for creating your Teams app](tools-prerequisites.md)
platform Debug Background Process https://github.com/MicrosoftDocs/msteams-docs/commits/main/msteams-platform/toolkit/debug-background-process.md
The debug process workflow is as follows:
1. `launch.json` file configures the debugger in Visual Studio Code.
-2. Visual Studio Code runs the compound **preLaunchTask**, **Pre Debug Check & Start All** in `.vscode/tasks.json` file.
+2. Visual Studio Code runs the compound **preLaunchTask**, **Start Teams App Locally** in `.vscode/tasks.json` file.
3. Visual Studio Code then launches the debuggers specified in the compound configurations, such as **Attach to Bot**, **Attach to Backend**, **Attach to Frontend**, and **Launch Bot**. 4. Microsoft Edge or Google Chrome launches a new browser instance and opens a web page to load Teams client.
-## Teams Toolkit verification of prerequisites
+## Verification of prerequisites
Teams Toolkit checks the following prerequisites during the debug process:
Teams Toolkit checks the following prerequisites during the debug process:
* Teams Toolkit prompts you to sign-in to Microsoft 365 account, if you haven't signed in with your valid credentials. * Custom app uploading or sideloading for your developer tenant is turned on, to prevent local debug termination.
-* Teams Toolkit installs Ngrok NPM package `ngrok@4.2.2` in `~/.fx/bin/ngrok`, if Ngrok isn't installed or the version doesn't match the requirement. Ngrok NPM package in `/.fx/bin/ngrok/node modules/ngrok/bin` manages the Ngrok binary version 2.3 that is applicable for bot and message extension.
-* Teams Toolkit installs Azure Functions Core Tools NPM package, azure-functions-core-tools@3 for **Windows** and **macOs** in `~/.fx/bin/func`, if Azure Functions Core Tools version 3 isn't installed or the version doesn't match the requirement. The Azure Functions Core Tools NPM package in `~/.fx/bin/func/node_modules/azure-functions-core-tools/bin` manages Azure Functions Core Tools binary. For Linux, the local debug terminates.
-* Teams Toolkit installs .NET Core SDK for **Windows** and **MacOS** in `~/.fx/bin/dotnet`, if .NET Core SDK version applicable for Azure Functions isn't installed or the version doesn't match the requirement. For Linux, the local debug terminates.
* Teams Toolkit installs Ngrok NPM package `ngrok@4.2.2` in `~/.fx/bin/ngrok`, if Ngrok isn't installed or the version doesn't match the requirement. Ngrok binary version 2.3 is applicable for bot and message extension. The Ngrok binary is managed by Ngrok NPM package in `/.fx/bin/ngrok/node modules/ngrok/bin`. * Teams Toolkit installs Azure Functions Core Tools NPM package, azure-functions-core-tools@3 for **Windows** and **MacOs** in `~/.fx/bin/func`, if Azure Functions Core Tools version 4 isn't installed or the version doesn't match the requirement. The Azure Functions Core Tools NPM package in `~/.fx/bin/func/node_modules/azure-functions-core-tools/bin` manages Azure Functions Core Tools binary. For Linux, the local debug terminates. * Teams Toolkit installs .NET Core SDK for **Windows** and **MacOS** in `~/.fx/bin/dotnet`.NET Core SDK version applicable for Azure Functions, if .NET Core SDK isn't installed or the version doesn't match the requirement. For Linux, the local debug terminates.
Use the following .NET Core versions:
When you select **Start Debugging (F5)**, the Teams Toolkit output channel displays the progress and result after checking the prerequisites.
- :::image type="content" source="../assets/images/teams-toolkit-v2/debug/prerequisites-debugcheck.png" alt-text="Prerequisites check summary" lightbox="../assets/images/teams-toolkit-v2/debug/prerequisites-debugcheck.png":::
+ :::image type="content" source="../assets/images/teams-toolkit-v2/debug/prerequisites-debugcheck1.png" alt-text="Prerequisites check summary" lightbox="../assets/images/teams-toolkit-v2/debug/prerequisites-debugcheck1.png":::
## Register and configure Teams app
platform Debug Local https://github.com/MicrosoftDocs/msteams-docs/commits/main/msteams-platform/toolkit/debug-local.md
Teams Toolkit helps you to debug and preview your Microsoft Teams app locally. D
Teams Toolkit in Visual Studio Code gives you the features to automate debugging of your Teams app locally. Visual Studio allows you to debug tab, bot, and message extension. You need to set up Teams Toolkit before you debug your app.
+> [!NOTE]
+>
+> You can upgrade your old Teams Toolkit project to use new tasks, for more information see [debug settings doc](https://aka.ms/teamsfx-debug-upgrade-new-tasks)
+ ## Set up your Teams Toolkit for debugging The following steps help you to set up your Teams Toolkit before you initiate the debug process:
Runs tasks as defined in `.vscode/tasks.json`.
The following image displays task names in the **OUTPUT** and **TERMINAL** tabs of the Visual Studio Code while running tab, bot or message extension, and Azure Functions. ### Launches debug configurations
platform Debug Overview https://github.com/MicrosoftDocs/msteams-docs/commits/main/msteams-platform/toolkit/debug-overview.md
Ensure that you can toggle breakpoints on the source codes of tabs, bots, messag
## Customize debug settings
-Teams Toolkit unchecks some prerequisites and allows you to customize the debug settings to create your tab or bot:
+Teams Toolkit allows you to customize the debug settings to create your tab or bot. For more information on the full list of customizable options, see [debug settings doc](https://aka.ms/teamsfx-debug-tasks).
+
+### Customize Scenarios
<br> <details>
-<summary><b>Use your bot endpoint</b></summary>
-1. In Visual Studio Code settings, you need to uncheck **Ensure Ngrok is installed and started (ngrok)**.
+<summary><b>Skip prerequisite checks</b></summary>
-1. You can set `siteEndpoint` configuration in `.fx/configs/config.local.json` to your endpoint.
+In `.fx/configs/tasks.json` under `"Validate & install prerequisites"` > `"args"` > `"prerequisites"`, update the prerequisite checks you wish to skip.
-```json
-{
- "bot": {
- "siteEndpoint": "https://your-bot-tunneling-url"
- }
-}
+ :::image type="content" source="../assets/images/teams-toolkit-v2/debug/skip-prerequisite-checks.png" alt-text="skip the prerequisite checks":::
-```
+</details>
+
+<details>
+<summary><b>Use your development certificate</b></summary>
+1. In `.fx/configs/tasks.json`, uncheck `"devCert"` under `"Validate & install prerequisites"` > `"args"` > `"prerequisites"`.
+1. Set "SSL_CRT_FILE" and "SSL_KEY_FILE" in `.env.teamsfx.local` to your certificate file path and key file path.
</details> <details>
-<summary><b>Use your development certificate</b></summary>
+<summary><b>Customize npm install args</b></summary>
-1. In Visual Studio Code settings, you need to uncheck **Ensure development certificate is trusted (devCert)**.
+In `.fx/configs/tasks.json`, set npmInstallArgs under `"Install npm packages"`.
+
+ :::image type="content" source="../assets/images/teams-toolkit-v2/debug/customize-npm-install.png" alt-text="Install npm package":::
-1. You can set `sslCertFile` and `sslKeyFile` configuration in `.fx/configs/config.local.json` to your certificate file path and key file path.
+</details>
-```json
-{
- "frontend": {
- "sslCertFile": "",
- "sslKeyFile": ""
- }
-}
-```
+<details>
+<summary><b>Modify ports</b></summary>
+* Bot
+ 1. Search for `"3978"` across your project and look for appearances in `tasks.json`, `ngrok.yml` and `index.js`.
+ 1. Replace it with your port.
+ :::image type="content" source="../assets/images/teams-toolkit-v2/debug/modify-ports-bot.png" alt-text="Replace your port for bot":::
+* Tab
+ 1. In `.fx/configs/tasks.json`, search for `"53000"`.
+ 1. Replace it with your port.
+ :::image type="content" source="../assets/images/teams-toolkit-v2/debug/modify-ports-tab.png" alt-text="Replace your port for tab":::
</details> <details>
-<summary><b>Use your start scripts to start app services</b></summary>
+<summary><b>Use your own app package</b></summary>
-1. For tab, you need to update `dev:teamsfx` script in `tabs/package.json`.
+In `.fx/configs/tasks.json`, set `"appPackagePath"` under `"Build & upload Teams manifest"` to your app package's path.
-1. For bot or message extension, you need to update `dev:teamsfx` script in `bot/package.json`.
+ :::image type="content" source="../assets/images/teams-toolkit-v2/debug/app-package-path.png" alt-text="use your own app package path":::
-1. For Azure Functions, you need to update `dev:teamsfx` script in `api/package.json` and for TypeScript update `watch:teamsfx` script.
+</details>
- > [!NOTE]
- > Currently, the tab, bot, message extension apps, and Azure Functions ports don't support customization.
+<details>
+<summary><b>Use your own tunnel</b></summary>
+
+1. In `.fx/configs/tasks.json` under `"Start Teams App Locally"`, you can update `"Start Local tunnel"`.
+
+ :::image type="content" source="../assets/images/teams-toolkit-v2/debug/start-local-tunnel.png" alt-text="Use your own tunnel":::
+1. Launch your own tunnel service then update `"botMessagingEndpoint"` to your own message endpoint in `.fx/configs/tasks.json` under `"Set up bot"`.
+
+ :::image type="content" source="../assets/images/teams-toolkit-v2/debug/set-up-bot.png" alt-text="update messaging endpoint":::
</details> <details>+ <summary><b>Add environment variables</b></summary> You can add environment variables to `.env.teamsfx.local` file for tab, bot, message extension, and Azure Functions. Teams Toolkit loads the environment variables you added to start services during local debug. > [!NOTE]
- > Ensure to start a new local debug after you add new environment variables as the environment variables don't support hot reload.
+ > Ensure to start a new local debug after you add new environment variables, as the environment variables don't support hot reload.
</details>
You can add environment variables to `.env.teamsfx.local` file for tab, bot, mes
Teams Toolkit utilizes Visual Studio Code multi-target debugging to debug tab, bot, message extension, and Azure Functions at the same time. You can update `.vscode/launch.json` and `.vscode/tasks.json` to debug partial component. If you want to debug tab only in a tab plus bot with Azure Functions project, use the following steps:
-1. Comment **`Attach to Bot`** and **`Attach to Backend`** from debug compound in `.vscode/launch.json`.
+1. Update `"Attach to Bot"` and `"Attach to Backend"` from debug compound in `.vscode/launch.json`.
```json {
Teams Toolkit utilizes Visual Studio Code multi-target debugging to debug tab, b
} ```
-2. Comment **`Start Backend`** and Start Bot from Start All task in .vscode/tasks.json.
+2. Update `"Start Backend"` and `"Start Bot"` from Start All task in .vscode/tasks.json.
```json {