OfficeDev / TeamsFx

Developer tools for building Teams apps
Other
427 stars 165 forks source link

Add Chatbot to existing MS Team Tabs Application but I run provision failed #7968

Closed thanhnguyen0504 closed 1 year ago

thanhnguyen0504 commented 1 year ago

Thank Team. The issue was fixed

ghost commented 1 year ago

Thank you for contacting us! Any issue or feedback from you is quite important to us. We will do our best to fully respond to your issue as soon as possible. Sometimes additional investigations may be needed, we will usually get back to you within 2 days by adding comments to this issue. Please stay tuned.

hund030 commented 1 year ago

@thanhnguyen0504 Thanks for reporting the issue. Seems you are using the latest Teams Toolkit and adding new feature to an existing project, which is created by an older version Teams Toolkit. So, Teams Toolkit add some incompatible bicep content. We will investigate in it and try to fix. To workaround, you can remove azureFunctionApiConfig.bicep file and the related module in config.bicep: image

thanhnguyen0504 commented 1 year ago

The issue was solved. For security, I delete all the conversations.

hund030 commented 1 year ago

==> Question: This change makes my Application's SSO feature work incorrectly. Why teams toolkit need to change this, can I change it back?

@thanhnguyen0504 Teams client checks the tab domain the same as the hostname in application id uri. The client id is to ensure the application id uri unique. For bot, Teams client checks the bot id in application id uri, so when there are both tab and bot, api://{tabDomain}/bot-id-{botId} is correct format.

I'm not sure if your SSO feature requires the client id must be contained in application id uri. You can change it back, as long as you don't use SSO feature in bot.

For the Bad Request issue. I follow your steps and reproduce the issue once. After I close the error message window, I found my app is successfully installed and worked well. And I didn't meet the issue again even I create a new environment. Maybe it's caused by teams api. Could you try again?

image
thanhnguyen0504 commented 1 year ago

==> Question: This change makes my Application's SSO feature work incorrectly. Why teams toolkit need to change this, can I change it back?

@thanhnguyen0504 Teams client checks the tab domain the same as the hostname in application id uri. The client id is to ensure the application id uri unique. For bot, Teams client checks the bot id in application id uri, so when there are both tab and bot, api://{tabDomain}/bot-id-{botId} is correct format.

I'm not sure if your SSO feature requires the client id must be contained in application id uri. You can change it back, as long as you don't use SSO feature in bot.

For the Bad Request issue. I follow your steps and reproduce the issue once. After I close the error message window, I found my app is successfully installed and worked well. And I didn't meet the issue again even I create a new environment. Maybe it's caused by teams api. Could you try again? image

Hi @hund030 ,

I have just tried it again but it's still failed. I tried with another manifest package without bot and it works well. Do you have any hints or suggestions? The error is too general and I don't know what should I do next.

hund030 commented 1 year ago
{
  "$schema": "https://developer.microsoft.com/en-us/json-schemas/teams/v1.11/MicrosoftTeams.schema.json",
  "manifestVersion": "1.11",
  "version": "1.0.0",
  "id": "d6e6b535-d579-4334-a0fc-8e6c9587d996",
  "packageName": "com.microsoft.teams.extension",
  "developer": {
    "name": "Teams App, Inc.",
    "websiteUrl": "https://app0devdb6a99tab.z13.web.core.windows.net",
    "privacyUrl": "https://app0devdb6a99tab.z13.web.core.windows.net/index.html#/privacy",
    "termsOfUseUrl": "https://app0devdb6a99tab.z13.web.core.windows.net/index.html#/termsofuse"
  },
  "icons": {
    "color": "resources/color.png",
    "outline": "resources/outline.png"
  },
  "name": {
    "short": "app03092",
    "full": "Full name for app03092"
  },
  "description": {
    "short": "Short description of app03092",
    "full": "Full description of app03092"
  },
  "accentColor": "#FFFFFF",
  "bots": [
    {
      "botId": "406a113b-2d3a-4dcd-a28d-ec8ea2192128",
      "scopes": ["personal", "team", "groupchat"],
      "supportsFiles": false,
      "isNotificationOnly": false,
      "commandLists": [
        {
          "scopes": ["personal", "team", "groupchat"],
          "commands": [
            {
              "title": "welcome",
              "description": "Resend welcome card of this Bot"
            },
            {
              "title": "learn",
              "description": "Learn about Adaptive Card and Bot Command"
            }
          ]
        }
      ]
    }
  ],
  "composeExtensions": [],
  "configurableTabs": [
    {
      "configurationUrl": "https://app0devdb6a99tab.z13.web.core.windows.net/index.html#/config",
      "canUpdateConfiguration": true,
      "scopes": ["team", "groupchat"]
    }
  ],
  "staticTabs": [
    {
      "entityId": "index",
      "name": "Personal Tab",
      "contentUrl": "https://app0devdb6a99tab.z13.web.core.windows.net/index.html#/tab",
      "websiteUrl": "https://app0devdb6a99tab.z13.web.core.windows.net/index.html#/tab",
      "scopes": ["personal"]
    }
  ],
  "permissions": ["identity", "messageTeamMembers"],
  "validDomains": ["app0devdb6a99bot.azurewebsites.net"],
  "webApplicationInfo": {
    "id": "47b7802b-bcee-4950-b8b3-7e631df4a8f4",
    "resource": "api://app0devdb6a99tab.z13.web.core.windows.net/botid-406a113b-2d3a-4dcd-a28d-ec8ea2192128"
  }
}

@thanhnguyen0504 Here's my manifest. There is not too many error prone points. My package zip file should contains a manifest.json file in the top directory and a resources folder contains two png files, which are required as icon in the manifest.

image

You can first try unzip your package and review the manifest file.

thanhnguyen0504 commented 1 year ago

Hi @hund030

If I created a new application and add a chatbot, that manifest works. But with the existing project above, I didn't know what I'm doing wrong. Lets me share my manifest file. Could you please point out the potential issue that may cause the error:

{
    "$schema": "https://developer.microsoft.com/en-us/json-schemas/teams/v1.10/MicrosoftTeams.schema.json",
    "manifestVersion": "1.10",
    "localizationInfo": {
        "defaultLanguageTag": "en",
        "additionalLanguages": [
            {
                "languageTag": "ar",
                "file": "resources/ar.json"
            },
            {
                "languageTag": "da",
                "file": "resources/da.json"
            },
            {
                "languageTag": "de",
                "file": "resources/de.json"
            },
            {
                "languageTag": "en-gb",
                "file": "resources/en-gb.json"
            },
            {
                "languageTag": "es-es",
                "file": "resources/es-es.json"
            },
            {
                "languageTag": "es",
                "file": "resources/es.json"
            },
            {
                "languageTag": "fr-ca",
                "file": "resources/fr-ca.json"
            },
            {
                "languageTag": "fr",
                "file": "resources/fr.json"
            },
            {
                "languageTag": "hi",
                "file": "resources/hi.json"
            },
            {
                "languageTag": "hu",
                "file": "resources/hu.json"
            },
            {
                "languageTag": "id",
                "file": "resources/id.json"
            },
            {
                "languageTag": "it",
                "file": "resources/it.json"
            },
            {
                "languageTag": "ja",
                "file": "resources/ja.json"
            },
            {
                "languageTag": "ko",
                "file": "resources/ko.json"
            },
            {
                "languageTag": "nl",
                "file": "resources/nl.json"
            },
            {
                "languageTag": "no",
                "file": "resources/no.json"
            },
            {
                "languageTag": "pl",
                "file": "resources/pl.json"
            },
            {
                "languageTag": "pt-br",
                "file": "resources/pt-br.json"
            },
            {
                "languageTag": "pt-pt",
                "file": "resources/pt-pt.json"
            },
            {
                "languageTag": "ro",
                "file": "resources/ro.json"
            },
            {
                "languageTag": "sv",
                "file": "resources/sv.json"
            },
            {
                "languageTag": "zh-cn",
                "file": "resources/zh-cn.json"
            }
        ]
    },
    "version": "1.0.38",
    "id": "61d0212a-b3ed-40e4-a622-5ea4ecb3dcbe",
    "packageName": "com.microsoft.teams.extension",
    "developer": {
        "name": "New Dev Teams App ",
        "websiteUrl": "https://www.mycompany.com",
        "privacyUrl": "https://mycompany.com/Privacy.aspx",
        "termsOfUseUrl": "https://mycompany.com/tos.aspx",
        "mpnId": "1210201"
    },
    "icons": {
        "color": "color.png",
        "outline": "outline.png"
    },
    "name": {
        "short": "New Dev Teams App ",
        "full": "Full name for mycompany Teams App New Dev"
    },
    "description": {
        "short": "Experience your mycompany well-being program in Microsoft teams",
        "full": "mycompany for teams is well-being in the flow of work. Track activities in your plan, discover new activities and see personal insights and collaborate with team activities"
    },
    "accentColor": "#FFFFFF",
    "bots": [
        {
            "botId": "8380c333-981f-4d65-98f2-ffd69fa59759",
            "scopes": [
                "personal",
                "team",
                "groupchat"
            ],
            "supportsFiles": false,
            "isNotificationOnly": false
        }
    ],
    "composeExtensions": [],
    "configurableTabs": [
        {
            "configurationUrl": "https://teamsappnewdev.mycompany.io/index.html#/config",
            "canUpdateConfiguration": true,
            "scopes": [
                "team",
                "groupchat"
            ]
        }
    ],
    "staticTabs": [
        {
            "entityId": "home",
            "name": "Home",
            "contentUrl": "https://teamsappnewdev.mycompany.io/index.html#/home",
            "scopes": [
                "personal"
            ]
        },
        {
            "entityId": "discover",
            "name": "Discover",
            "contentUrl": "https://teamsappnewdev.mycompany.io/index.html#/discover",
            "scopes": [
                "personal"
            ]
        },
        {
            "entityId": "achievements",
            "name": "Achievements",
            "contentUrl": "https://teamsappnewdev.mycompany.io/index.html#/achievements",
            "scopes": [
                "personal"
            ]
        },
        {
            "entityId": "about",
            "scopes": [
                "personal"
            ]
        }
    ],
    "permissions": [
        "identity",
        "messageTeamMembers"
    ],
    "devicePermissions": [
        "notifications"
    ],
    "validDomains": [
        "teamsappnewdev.mycompany.io",
        "mycompanyteanewdab6008bot.azurewebsites.net"
    ],
    "webApplicationInfo": {
        "id": "7b1e25d8-da5c-465a-bce5-2733384a7828",
        "resource": "api://teamsappnewdev.mycompany.io/botid-8380c333-981f-4d65-98f2-ffd69fa59759"
    },
    "configurableProperties": [
        "name",
        "shortDescription",
        "longDescription",
        "smallImageUrl",
        "largeImageUrl",
        "accentColor"
    ],
    "activities": {
        "activityTypes": [
            {
                "type": "Invitation",
                "description": "You are invited to a team to work on activity",
                "templateText": "{actor} invited you to take part in {activityName}"
            },
            {
                "type": "Nudge",
                "description": "Keep going! Track your progress on your well-being now.",
                "templateText": "Keep going! Track your progress on your well-being now."
            },
            {
                "type": "EndingActivity",
                "description": "⏳ Time is almost up!",
                "templateText": "⏳ Time is almost up!"
            },
            {
                "type": "Cheers",
                "description": "{actor} sent cheers to you!",
                "templateText": "{actor} sent cheers to you!"
            },
            {
                "type": "JoinTeam",
                "description": "🎉 {actor} just joined your team. Cheer them on!",
                "templateText": "🎉 {actor} just joined your team. Cheer them on!"
            },
            {
                "type": "TeamPosition",
                "description": "Your team now at {position} place",
                "templateText": "Your team now at {position} place"
            },
            {
                "type": "CompleteActivity",
                "description": "🏆 Well Done {teamName}",
                "templateText": "🏆 Well Done {teamName}"
            }
        ]
    }
}

After you check my manifest file. Do you know which config values are wrong or abnormal?

hund030 commented 1 year ago

@thanhnguyen0504 I replace my manifest with yours, replacing the bot id with mine (since we are not in the same tenant) and remove the localizationInfo section. Then I can install the application successfully. The folder structure is as below. Suppose your language files are in resources folder.

image

Could you check the diff of the manifest after adding bot? I don't think the manifest is invalid if the resources are in right places.

thanhnguyen0504 commented 1 year ago

@thanhnguyen0504 I replace my manifest with yours, replacing the bot id with mine (since we are not in the same tenant) and remove the localizationInfo section. Then I can install the application successfully. The folder structure is as below. Suppose your language files are in resources folder. image

Could you check the diff of the manifest after adding bot? I don't think the manifest is invalid if the resources are in right places.

Here is the diff between before and after adding bot: image

image

Do you think the values of configuration above are point to wrong values. I checked and found that webApplicationInfo.resource is point to Application ID URI of App Registration of my Application image

And 8380c333-981f-4d65-98f2-ffd69fa59759 is the clientid of Chat Bot's App Registration: image

That means we have 2 app registrations (Tab Application and one Chat Bot)

Do you think that's not problem of manifest file but it's a problem of Provision or Deployment the cloud resource to Azure?

hund030 commented 1 year ago

@thanhnguyen0504 I don't think it's related to your cloud resources. While you could try reverting the webApplicationInfo.resource in manifest and see if it mitigates the issue. We are connecting with Teams Dev Portal team to figure out the api failure.

thanhnguyen0504 commented 1 year ago

@thanhnguyen0504 I don't think it's related to your cloud resources. While you could try reverting the webApplicationInfo.resource in manifest and see if it mitigates the issue. We are connecting with Teams Dev Portal team to figure out the api failure.

Hi @hund030 Do you have any news?

From my side. I reverted the Manifest package to the time before adding Chat Bot and upload the package and then I can install the Application as well.

hund030 commented 1 year ago

@thanhnguyen0504 It's recommended that validating your package zip in Teams dev portal first.

image
thanhnguyen0504 commented 1 year ago

@thanhnguyen0504 It's recommended that validating your package zip in Teams dev portal first. image

I tried this and didn't find any issue: image

There are some warnings and they're not related to our failure case.

thanhnguyen0504 commented 1 year ago

I'm thinking about sending you my manifest package so that you can try to upload and install the application. What do you think @hund030 ?

hund030 commented 1 year ago

I'm thinking about sending you my manifest package so that you can try to upload and install the application. What do you think @hund030 ?

Sure. It's ok to me. You can find my email from my GitHub profile.

thanhnguyen0504 commented 1 year ago

I'm thinking about sending you my manifest package so that you can try to upload and install the application. What do you think @hund030 ?

Sure. It's ok to me. You can find my email from my GitHub profile.

Thank you so much. I have sent you an email.

hund030 commented 1 year ago

Similar to https://github.com/OfficeDev/TeamsFx/issues/7608. The root cause is the bot id in manifest is invalid.

domix1996 commented 1 month ago

what will the aad.manifest.json look like ? I am trying to add api permissions to graph for tab and bot, but the aad.manifest.json in this project only assumes for one of them.... how can I update it for both ?

@hund030 @adashen @yukun-dong @thanhnguyen0504

blackchoey commented 1 month ago

@domix1996 The graph permissions (requiredResourceAccess) does not bind to tab or bot, so you don't need to define permissions for tab and bot repeatedly. Can you share more information about what you're trying to do or the problem you meet?

domix1996 commented 1 month ago

@blackchoey in general, I am trying to create an application with a bot (to be used in any or a specific channel) and a tab (as personal). I have tried to create a configuration for both with a range of permissions:

aad.manifest.json:

{
    "id": "${{AAD_APP_OBJECT_ID}}",
    "appId": "${{AAD_APP_CLIENT_ID}}",
    "name": "${{NAME_APP_AAD}}",
    "logoUrl": "${{APP_LOGO}}",
    "accessTokenAcceptedVersion": 2,
    "oauth2AllowIdTokenImplicitFlow": true,
    "oauth2AllowImplicitFlow": true,
    "signInAudience": "AzureADMultipleOrgs",
    "optionalClaims": {
        "idToken": [],
        "accessToken": [
            {
                "name": "idtyp",
                "source": null,
                "essential": false,
                "additionalProperties": []
            }
        ],
        "saml2Token": []
    },
    "requiredResourceAccess": [
        {
            "resourceAppId": "Microsoft Graph",
            "resourceAccess": [
                {
                    "id": "AuditLog.Read.All",
                    "type": "Scope"
                },
                {
                    "id": "ChannelMessage.Read.All",
                    "type": "Scope"
                },
                {
                    "id": "Directory.AccessAsUser.All",
                    "type": "Scope"
                },
                {
                    "id": "Directory.Read.All",
                    "type": "Scope"
                },
                {
                    "id": "Directory.ReadWrite.All",
                    "type": "Scope"
                },
                {
                    "id": "email",
                    "type": "Scope"
                },
                {
                    "id": "Group.ReadWrite.All",
                    "type": "Scope"
                },
                {
                    "id": "openid",
                    "type": "Scope"
                },
                {
                    "id": "profile",
                    "type": "Scope"
                },
                {
                    "id": "TeamMember.Read.All",
                    "type": "Scope"
                },
                {
                    "id": "TeamMember.ReadWrite.All",
                    "type": "Scope"
                },
                {
                    "id": "TeamMember.Read.All",
                    "type": "Scope"
                },
                {
                    "id": "TeamMember.ReadWrite.All",
                    "type": "Scope"
                },
                {
                    "id": "User.Read",
                    "type": "Scope"
                },
                {
                    "id": "User.Read.All",
                    "type": "Scope"
                },
                {
                    "id": "User.ReadWrite.All",
                    "type": "Scope"
                }
            ]
        }
    ],
    "oauth2Permissions": [
        {
            "adminConsentDescription": "Allows Teams to call the app's web APIs as the current user.",
            "adminConsentDisplayName": "Teams can access app's web APIs",
            "id": "${{AAD_APP_ACCESS_AS_USER_PERMISSION_ID}}",
            "isEnabled": true,
            "type": "User",
            "userConsentDescription": "Enable Teams to call this app's web APIs with the same rights that you have",
            "userConsentDisplayName": "Teams can access app's web APIs and make requests on your behalf",
            "value": "access_as_user"
        }
    ],
    "preAuthorizedApplications": [
        {
            "appId": "1fec8e78-bce4-4aaf-ab1b-5451cc387264",
            "permissionIds": ["${{AAD_APP_ACCESS_AS_USER_PERMISSION_ID}}"]
        },
        {
            "appId": "5e3ce6c0-2b1f-4285-8d4b-75ee78787346",
            "permissionIds": ["${{AAD_APP_ACCESS_AS_USER_PERMISSION_ID}}"]
        },
        {
            "appId": "d3590ed6-52b3-4102-aeff-aad2292ab01c",
            "permissionIds": ["${{AAD_APP_ACCESS_AS_USER_PERMISSION_ID}}"]
        },
        {
            "appId": "00000002-0000-0ff1-ce00-000000000000",
            "permissionIds": ["${{AAD_APP_ACCESS_AS_USER_PERMISSION_ID}}"]
        },
        {
            "appId": "bc59ab01-8403-45c6-8796-ac3ef710b3e3",
            "permissionIds": ["${{AAD_APP_ACCESS_AS_USER_PERMISSION_ID}}"]
        },
        {
            "appId": "0ec893e0-5785-4de6-99da-4ed124e5296c",
            "permissionIds": ["${{AAD_APP_ACCESS_AS_USER_PERMISSION_ID}}"]
        },
        {
            "appId": "4765445b-32c6-49b0-83e6-1d93765276ca",
            "permissionIds": ["${{AAD_APP_ACCESS_AS_USER_PERMISSION_ID}}"]
        },
        {
            "appId": "4345a7b9-9a63-4910-a426-35363201d503",
            "permissionIds": ["${{AAD_APP_ACCESS_AS_USER_PERMISSION_ID}}"]
        },
        {
            "appId": "04b07795-8ddb-461a-bbee-02f9e1bf7b46",
            "permissionIds": ["${{AAD_APP_ACCESS_AS_USER_PERMISSION_ID}}"]
        }
    ],
    "identifierUris": ["api://botid-${{BOT_ID}}"],
    "replyUrlsWithType": [
        {
            "url": "https://${{BOT_DOMAIN}}/auth-end.html",
            "type": "Web"
        },
        {
            "url": "https://${{TAB_DOMAIN}}/auth-end.html",
            "type": "Spa"
        }
    ]
}

The infra folder looks as follows:

azure.bicep:

@maxLength(20)
@minLength(4)
param resourceBaseName string
param storageSku string

@description('Required when create Azure Bot service')
param botAadAppClientId string

@secure()
@description('Required by Bot Framework package in your bot project')
param botAadAppClientSecret string

param webAppSKU string

@maxLength(42)
param botDisplayName string

param serverfarmsName string = resourceBaseName
param webAppName string = resourceBaseName

param storageName string = resourceBaseName
param location string = resourceGroup().location
param aadAppClientId string
param aadAppTenantId string
param aadAppOauthAuthorityHost string
@secure()
param aadAppClientSecret string

// Azure Storage that hosts your static web site
resource storage 'Microsoft.Storage/storageAccounts@2021-06-01' = {
  kind: 'StorageV2'
  location: location
  name: storageName
  properties: {
    supportsHttpsTrafficOnly: true
  }
  sku: {
    name: storageSku
  }
}

// Compute resources for your Web App
resource serverfarm 'Microsoft.Web/serverfarms@2021-02-01' = {
  kind: 'app'
  location: location
  name: serverfarmsName
  sku: {
    name: webAppSKU
  }
}

// Web App that hosts your bot
resource webApp 'Microsoft.Web/sites@2021-02-01' = {
  kind: 'app'
  location: location
  name: webAppName
  properties: {
    serverFarmId: serverfarm.id
    httpsOnly: true
    siteConfig: {
      alwaysOn: false
      ftpsState: 'FtpsOnly'
    }
  }
}

resource webAppSettings 'Microsoft.Web/sites/config@2021-02-01' = {
  name: '${webAppName}/appsettings'
  properties: {
    WEBSITE_RUN_FROM_PACKAGE: '1'
    MicrosoftAppId: botAadAppClientId
    MicrosoftAppPassword: botAadAppClientSecret
    BOT_DOMAIN: webApp.properties.defaultHostName
    AAD_APP_CLIENT_ID: aadAppClientId
    AAD_APP_CLIENT_SECRET: aadAppClientSecret
    AAD_APP_TENANT_ID: aadAppTenantId
    AAD_APP_OAUTH_AUTHORITY_HOST: aadAppOauthAuthorityHost
    RUNNING_ON_AZURE: '1'
  }
}

// Register your web service as a bot with the Bot Framework
module azureBotRegistration './botRegistration/azurebot.bicep' = {
  name: 'Azure-Bot-registration'
  params: {
    resourceBaseName: resourceBaseName
    botAadAppClientId: botAadAppClientId
    botAppDomain: webApp.properties.defaultHostName
    botDisplayName: botDisplayName
  }
}

var siteDomain = replace(replace(storage.properties.primaryEndpoints.web, 'https://', ''), '/', '')

// The output will be persisted in .env.{envName}. Visit https://aka.ms/teamsfx-actions/arm-deploy for more details.
output TAB_AZURE_STORAGE_RESOURCE_ID string = storage.id // used in deploy stage
output TAB_DOMAIN string = siteDomain
output TAB_ENDPOINT string = 'https://${siteDomain}'
output BOT_AZURE_APP_SERVICE_RESOURCE_ID string = webApp.id
output BOT_DOMAIN string = webApp.properties.defaultHostName

azurebot.bicep:

@maxLength(20)
@minLength(4)
@description('Used to generate names for all resources in this file')
param resourceBaseName string

@maxLength(42)
param botDisplayName string

param botServiceName string = resourceBaseName
param botServiceSku string = 'F0'
param botAadAppClientId string
param botAppDomain string

// Register your web service as a bot with the Bot Framework
resource botService 'Microsoft.BotService/botServices@2021-03-01' = {
  kind: 'azurebot'
  location: 'global'
  name: botServiceName
  properties: {
    displayName: botDisplayName
    endpoint: 'https://${botAppDomain}/api/messages'
    msaAppId: botAadAppClientId
  }
  sku: {
    name: botServiceSku
  }
}

// Connect the bot service to Microsoft Teams
resource botServiceMsTeamsChannel 'Microsoft.BotService/botServices/channels@2021-03-01' = {
  parent: botService
  location: 'global'
  name: 'MsTeamsChannel'
  properties: {
    channelName: 'MsTeamsChannel'
  }
}

azure.parameters.json:

{
    "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#",
    "contentVersion": "1.0.0.0",
    "parameters": {
        "resourceBaseName": {
            "value": "app${{RESOURCE_SUFFIX}}"
        },
        "storageSku": {
            "value": "Standard_LRS"
        },
        "botAadAppClientId": {
            "value": "${{BOT_ID}}"
        },
        "botAadAppClientSecret": {
            "value": "${{SECRET_BOT_PASSWORD}}"
        },
        "webAppSKU": {
            "value": "F1"
        },
        "botDisplayName": {
            "value": "... Bot"
        },
        "aadAppClientId": {
            "value": "${{AAD_APP_CLIENT_ID}}"
        },
        "aadAppClientSecret": {
            "value": "${{SECRET_AAD_APP_CLIENT_SECRET}}"
        },
        "aadAppTenantId": {
            "value": "${{AAD_APP_TENANT_ID}}"
        },
        "aadAppOauthAuthorityHost": {
            "value": "${{AAD_APP_OAUTH_AUTHORITY_HOST}}"
        }
    }
}

and finally manifest.json:

{
    "$schema": "https://developer.microsoft.com/en-us/json-schemas/teams/v1.16/MicrosoftTeams.schema.json",
    "version": "1.1.5",
    "manifestVersion": "1.16",
    "id": "${{TEAMS_APP_ID}}",
    "packageName": "com.microsoft.teams.extension",
    "name": {
        "short": "${{NAME_APP_TEAMS}}",
        "full": "... Sp. z o.o. "
    },
    "developer": {
        "name": "Teams App, Inc.",
        "websiteUrl": "${{TAB_ENDPOINT}}",
        "privacyUrl": "${{TAB_ENDPOINT}}/privacy",
        "termsOfUseUrl": "${{TAB_ENDPOINT}}/termsofuse"
    },
    "description": {
        "short": "Short description of ...",
        "full": "Full description of ..."
    },
    "icons": {
        "outline": "outline.png",
        "color": "color.png"
    },
    "accentColor": "#FFFFFF",
    "staticTabs": [
        {
            "entityId": "xxx",
            "name": "Xxx",
            "contentUrl": "${{TAB_ENDPOINT}}/index.html#/xxx",
            "websiteUrl": "${{TAB_ENDPOINT}}/index.html#/xxx",
            "scopes": ["personal"]
        },
        {
            "entityId": "yyy",
            "name": "Yyy",
            "contentUrl": "${{TAB_ENDPOINT}}/index.html#/yyy",
            "websiteUrl": "${{TAB_ENDPOINT}}/yyy",
            "scopes": ["personal"]
        },
        {
            "entityId": "zzz",
            "name": "Zzz",
            "contentUrl": "${{TAB_ENDPOINT}}/index.html#/zzz",
            "websiteUrl": "${{TAB_ENDPOINT}}/index.html#/zzz",
            "scopes": ["personal"]
        },
        {
            "entityId": "yzx",
            "name": "Yzx",
            "contentUrl": "${{TAB_ENDPOINT}}/index.html#/yzx",
            "websiteUrl": "${{TAB_ENDPOINT}}/index.html#/yzx",
            "scopes": ["team", "groupChat"]
        }
    ],

    "bots": [
        {
            "botId": "${{BOT_ID}}",
            "scopes": ["team", "groupChat"],
            "isNotificationOnly": false,
            "supportsCalling": false,
            "supportsVideo": false,
            "supportsFiles": true,
            "commandLists": [
                {
                    "scopes": ["team", "groupChat"],
                    "commands": [
                        {
                            "title": "selfie",
                            "description": "Show user profile using Graph"
                        }
                    ]
                }
            ]
        }
    ],
    "composeExtensions": [
        {
            "botId": "${{BOT_ID}}",
            "commands": [
                {
                    "id": "createCard",
                    "context": ["compose"],
                    "description": "Command to run action to create a Card from Compose Box",
                    "title": "createCardddd",
                    "type": "action",
                    "parameters": [
                        {
                            "name": "title",
                            "title": "Card title",
                            "description": "Title for the card",
                            "inputType": "text"
                        },
                        {
                            "name": "subTitle",
                            "title": "Subtitle",
                            "description": "Subtitle for the card",
                            "inputType": "text"
                        },
                        {
                            "name": "text",
                            "title": "Text",
                            "description": "Text for the card",
                            "inputType": "textarea"
                        }
                    ]
                },
                {
                    "id": "createTask",
                    "context": ["compose"],
                    "description": "Command to run action to create a Card from Compose Box",
                    "title": "Create Task",
                    "type": "action",
                    "parameters": [
                        {
                            "name": "...",
                            "title": "...",
                            "description": "...",
                            "inputType": "text"
                        },
                        {
                            "name": "...",
                            "title": "...",
                            "description": "...",
                            "inputType": "text"
                        },
                        {
                            "name": "...",
                            "title": "...",
                            "description": "...",
                            "inputType": "textarea"
                        }
                    ]
                },
                {
                    "id": "shareMessage",
                    "context": ["message"],
                    "description": "Test command to run action on message context (message sharing)",
                    "title": "Share Message",
                    "type": "action",
                    "parameters": [
                        {
                            "name": "includeImage",
                            "title": "Include Image",
                            "description": "Include image in Hero Card",
                            "inputType": "toggle"
                        }
                    ]
                },
                { 
                    "id": "searchQuery",
                    "context": ["compose", "commandBox"],
                    "description": "Test command to run query",
                    "title": "Search",
                    "type": "query",
                    "parameters": [
                        {
                            "name": "searchQuery",
                            "title": "Search Query",
                            "description": "Your search query",
                            "inputType": "text"
                        }
                    ]
                }
            ]
        }
    ],
    "permissions": ["identity", "messageTeamMembers"],
    "validDomains": ["${{BOT_DOMAIN}}", "${{TAB_DOMAIN}}"],
    "webApplicationInfo": {
        "id": "${{AAD_APP_CLIENT_ID}}",
        "resource": "api://botid-${{BOT_ID}}"
    }
}

teamsapp.local.yml:

version: v1.2

additionalMetadata:
  sampleTag: TeamsFx-...:full_app

provision:
  - uses: aadApp/create
    with:
      name: ..._Teams_${{TEAMSFX_ENV}}${{APP_PSEUDO}}
      generateClientSecret: true
      signInAudience: 'AzureADMultipleOrgs'
    writeToEnvironmentFile:
      clientId: AAD_APP_CLIENT_ID
      clientSecret: SECRET_AAD_APP_CLIENT_SECRET
      objectId: AAD_APP_OBJECT_ID
      tenantId: AAD_APP_TENANT_ID
      authority: AAD_APP_OAUTH_AUTHORITY
      authorityHost: AAD_APP_OAUTH_AUTHORITY_HOST

  - uses: teamsApp/create
    with:
      name: Flask_MS_Teams_SDK_${{TEAMSFX_ENV}}${{APP_PSEUDO}}
    writeToEnvironmentFile:
      teamsAppId: TEAMS_APP_ID

  - uses: botAadApp/create
    with:
      name: bot${{APP_NAME_SUFFIX}}${{APP_PSEUDO}}
    writeToEnvironmentFile:
      botId: BOT_ID
      botPassword: SECRET_BOT_PASSWORD

  - uses: botFramework/create
    with:
      botId: ${{BOT_ID}}
      name: flask-bot${{APP_PSEUDO}}
      messagingEndpoint: ${{BOT_ENDPOINT}}/api/messages
      description: ''
      channels:
        - name: msteams

  - uses: aadApp/update
    with:
      manifestPath: './aad.manifest.json'
      outputFilePath: ./build/aad.manifest.${{TEAMSFX_ENV}}.json

  - uses: script
    with:
      run: echo "::set-teamsfx-env TAB_DOMAIN=localhost:53000"; echo
        "::set-teamsfx-env TAB_ENDPOINT=https://localhost:53000";

  - uses: teamsApp/validateManifest
    with:
      manifestPath: ./appPackage/manifest.json

  - uses: teamsApp/zipAppPackage
    with:
      manifestPath: ./appPackage/manifest.json
      outputZipPath: ./appPackage/build/appPackage.${{TEAMSFX_ENV}}.zip
      outputJsonPath: ./appPackage/build/manifest.${{TEAMSFX_ENV}}.json

  - uses: teamsApp/validateAppPackage
    with:
      appPackagePath: ./appPackage/build/appPackage.${{TEAMSFX_ENV}}.zip

  - uses: teamsApp/update
    with:
      appPackagePath: ./appPackage/build/appPackage.${{TEAMSFX_ENV}}.zip

deploy:
  - uses: devTool/install
    with:
      devCert:
        trust: true
    writeToEnvironmentFile:
      sslCertFile: SSL_CRT_FILE
      sslKeyFile: SSL_KEY_FILE

  - uses: cli/runNpmCommand
    with:
      args: install --no-audit

  - uses: file/createOrUpdateEnvironmentFile
    with:
      target: ./tab/.localConfigs
      envs:
        BROWSER: none
        HTTPS: true
        PORT: 53000
        SSL_CRT_FILE: ${{SSL_CRT_FILE}}
        SSL_KEY_FILE: ${{SSL_KEY_FILE}}
        REACT_APP_CLIENT_ID: ${{AAD_APP_CLIENT_ID}}
        REACT_APP_TENANT_ID: ${{AAD_APP_TENANT_ID}}
        REACT_APP_TAB_ENDPOINT: ${{TAB_ENDPOINT}}
        REACT_APP_START_LOGIN_PAGE_URL: ${{TAB_ENDPOINT}}/auth-start.html

  - uses: file/createOrUpdateEnvironmentFile
    with:
      target: ./bot/.localConfigs
      envs:
        BOT_ID: ${{BOT_ID}}
        BOT_PASSWORD: ${{SECRET_BOT_PASSWORD}}
        TENANT_ID: ${{AAD_APP_TENANT_ID}}
        TEAMS_APP_ID: ${{TEAMS_APP_ID}}
        BOT_DOMAIN: ${{BOT_DOMAIN}}
        AAD_APP_CLIENT_ID: ${{AAD_APP_CLIENT_ID}}
        AAD_APP_CLIENT_SECRET: ${{SECRET_AAD_APP_CLIENT_SECRET}}
        AAD_APP_TENANT_ID: ${{AAD_APP_TENANT_ID}}
        AAD_APP_OAUTH_AUTHORITY_HOST: ${{AAD_APP_OAUTH_AUTHORITY_HOST}}
        ClientId: ${{AAD_APP_CLIENT_ID}}
        ClientSecret: ${{SECRET_AAD_APP_CLIENT_SECRET}}
        OAuthAuthority: ${{AAD_APP_OAUTH_AUTHORITY}}
        ApplicationIdUri: api://botid-${{BOT_ID}}
        InitiateLoginEndpoint: https://${{BOT_DOMAIN}}/auth-start.html
projectId: xxxxx

teamsapp.yml:

version: v1.2

additionalMetadata:
  sampleTag: TeamsFx-Flask:msg-ext-with-tab

environmentFolderPath: ./env

provision:
  - uses: aadApp/create
    with:
      name: ..._${{TEAMSFX_ENV}}
      generateClientSecret: true
      signInAudience: 'AzureADMultipleOrgs'
    writeToEnvironmentFile:
      clientId: AAD_APP_CLIENT_ID
      clientSecret: SECRET_AAD_APP_CLIENT_SECRET
      objectId: AAD_APP_OBJECT_ID
      tenantId: AAD_APP_TENANT_ID
      authority: AAD_APP_OAUTH_AUTHORITY
      authorityHost: AAD_APP_OAUTH_AUTHORITY_HOST

  - uses: teamsApp/create
    with:
      name: ..._MS_Teams_SDK_${{TEAMSFX_ENV}}
    writeToEnvironmentFile:
      teamsAppId: TEAMS_APP_ID

  - uses: botAadApp/create
    with:
      name: bot${{APP_NAME_SUFFIX}}
    writeToEnvironmentFile:
      botId: BOT_ID
      botPassword: SECRET_BOT_PASSWORD

  - uses: arm/deploy
    with:
      subscriptionId: ${{AZURE_SUBSCRIPTION_ID}}
      resourceGroupName: ${{AZURE_RESOURCE_GROUP_NAME}}
      templates:
        - path: ./infra/azure.bicep
          parameters: ./infra/azure.parameters.json
          deploymentName: Create-resources
      bicepCliVersion: v0.9.1

  - uses: aadApp/update
    with:
      manifestPath: './aad.manifest.json'
      outputFilePath: ./build/aad.manifest.${{TEAMSFX_ENV}}.json

  - uses: teamsApp/validateManifest
    with:
      manifestPath: ./appPackage/manifest.json

  - uses: teamsApp/zipAppPackage
    with:
      manifestPath: ./appPackage/manifest.json
      outputZipPath: ./appPackage/build/appPackage.${{TEAMSFX_ENV}}.zip
      outputJsonPath: ./appPackage/build/manifest.${{TEAMSFX_ENV}}.json

  - uses: teamsApp/validateAppPackage
    with:
      appPackagePath: ./appPackage/build/appPackage.${{TEAMSFX_ENV}}.zip

  - uses: teamsApp/update
    with:
      appPackagePath: ./appPackage/build/appPackage.${{TEAMSFX_ENV}}.zip

  - uses: azureStorage/enableStaticWebsite
    with:
      storageResourceId: ${{TAB_AZURE_STORAGE_RESOURCE_ID}}
      indexPage: index.html
      errorPage: error.html
deploy:
  - uses: cli/runNpmCommand
    with:
      args: install

  - uses: cli/runNpmCommand
    with:
      args: run build

  - uses: azureStorage/deploy
    with:
      workingDirectory: tab
      artifactFolder: build
      resourceId: ${{TAB_AZURE_STORAGE_RESOURCE_ID}}

  - uses: azureAppService/zipDeploy
    with:
      workingDirectory: bot
      artifactFolder: .
      ignoreFile: .webappignore
      resourceId: ${{BOT_AZURE_APP_SERVICE_RESOURCE_ID}}
publish:
  - uses: teamsApp/validateManifest
    with:
      manifestPath: ./appPackage/manifest.json

  - uses: teamsApp/zipAppPackage
    with:
      manifestPath: ./appPackage/manifest.json
      outputZipPath: ./appPackage/build/appPackage.${{TEAMSFX_ENV}}.zip
      outputJsonPath: ./appPackage/build/manifest.${{TEAMSFX_ENV}}.json

  - uses: teamsApp/validateAppPackage
    with:
      appPackagePath: ./appPackage/build/appPackage.${{TEAMSFX_ENV}}.zip

  - uses: teamsApp/update
    with:
      appPackagePath: ./appPackage/build/appPackage.${{TEAMSFX_ENV}}.zip

  - uses: teamsApp/publishAppPackage
    with:
      appPackagePath: ./appPackage/build/appPackage.${{TEAMSFX_ENV}}.zip
    writeToEnvironmentFile:
      publishedAppId: TEAMS_APP_PUBLISHED_APP_ID
projectId: ...

Project structure: image

The bot is written in Typescript and Tab is written in React

When I run locally, everything works fine, however after deploy, the dev version of the app, most simply does not work.... as if there were further problems with the application configuration. I have two env files - local and dev.

Can you please take a look and point out what should be corrected and how to approach the problem, so that in the dev version, the application works correctly and starts to work with the settings?

As I wrote earlier, I want the tab and bot to work together in some way and be able to use the graph in the dev version.

I've looked through possible tutorials, I've also seen solutions for the bot with SSO, but as far as I know at the moment, the bot with SSO only works 1:1 in conversation and it doesn't work on teams. Therefore, for the moment of testing, I'm using Interactive Browser as an autoetition to Graph.

@hund030 @adashen @blackchoey @yukun-dong any suggestions or comments? are you able to help me?

blackchoey commented 1 month ago

Since it works locally, you can refer https://learn.microsoft.com/en-us/azure/app-service/troubleshoot-diagnostic-logs to figure out the errors for your app on Azure App Service and fix them accordingly. As you mentioned, it's also possible that the app settings are not configured correctly in your Azure App Service. You can refer https://learn.microsoft.com/en-us/azure/templates/microsoft.web/sites/config-appsettings?pivots=deployment-language-bicep to understand how to config the app settings via bicep.