Note
Access to this page requires authorization. You can try signing in or changing directories.
Access to this page requires authorization. You can try changing directories.
Microsoft Teams provides single sign-on (SSO) function for an app to obtain signed in Teams user token to access Microsoft Graph and other APIs. Microsoft 365 Agents Toolkit (previously known as Teams Toolkit) facilitates the interaction by abstracting some of the Microsoft Entra ID flows and integrations behind some simple APIs. This enables you to add SSO features easily to your Teams app.
Enable SSO in Agents Toolkit for Visual Studio
Teams provides SSO function for an app using Agents Toolkit for Microsoft Visual Studio.
Open Visual Studio.
Select Project > Microsoft 365 Agents Toolkit > Add Authentication Code.
Agents Toolkit helps you generate the authentication files in TeamsFx-Auth folder, including the app manifest (previously called Teams app manifest) template file for Microsoft Entra application and authentication redirect pages. Link the files to your Teams application by updating authentication configurations to ensure the SSO works for your application.
- In the Microsoft Entra app manifest file, specify the URIs (Uniform Resource Identifier) such as, the URI to identify the Microsoft Entra authentication app and the redirect URI for returning token.
- In the app manifest file, add the SSO application to link it with Teams application.
- Add SSO application information in Agents Toolkit configuration files in order to make sure the authentication app can be registered on backend service and start Agents Toolkit when you're debugging or previewing Teams application.
Teams tab application
Update Microsoft Entra app manifest:
TeamsFx-Auth/aad.manifest.template.jsonfile is a Microsoft Entra app manifest template. You can copy and paste this file to any folder of your project, and rename asaad.manifest.jsonand take note of the path to this file. The following updates in the template to create/update a Microsoft Entra app for SSO:identifierUris: It's used to uniquely identify and access the resource. Set the correct redirect URIs intoidentifierUristo successfully identify this app. For more information, see identifierUris attribute."identifierUris":[ "api://${{TAB_DOMAIN}}/${{AAD_APP_CLIENT_ID}}" ]redirectUris: It lists registered redirect_uri values that Microsoft Entra ID accepts as destinations when returning tokens. Set necessary redirect URIs intoredirectUristo successfully return token. For more information, see redirectUris attribute."web": { "redirectUris": [ "${{TAB_ENDPOINT}}/auth-end.html" ] }Note
Use
${{ENV_NAME}}to reference variables inenv/.env.{TEAMSFX_ENV}."web": { "redirectUris": [ "${{TAB_ENDPOINT}}/auth-end.html" ] }, "spa": { "redirectUris": [ "${{TAB_ENDPOINT}}/auth-end.html?clientId=${{AAD_APP_CLIENT_ID}}", "${{TAB_ENDPOINT}}/blank-auth-end.html" ] }"name": It replaces the value with your expected Microsoft Entra app name.
Open your app manifest file, add
WebApplicationInfoproperty with the value of your SSO app. For more information, see webApplicationInfo."webApplicationInfo": { "id": "${{AAD_APP_CLIENT_ID}}", "resource": "SAME_AS_YOUR_IDENTIFIERURIS" }Note
Update the value of resource to your
identifierUrisconfiged in step 1, and use${{ENV_NAME}}to reference envs inenv/.env.{TEAMSFX_ENV}.Open the
appPackage/manifest.jsonfile, and add the following code:"webApplicationInfo": { "id": "${{AAD_APP_CLIENT_ID}}", "resource": "api://${{TAB_DOMAIN}}/${{AAD_APP_CLIENT_ID}}" }Update the
m365agents.ymlfile and them365agents.local.ymlfile.Add Microsoft Entra related changes and configs into your
ymlfiles:Add
aadApp/createunderprovision: Create new Microsoft Entra apps used for SSO. For more information, see aadApp/create.Note
You can add any missing parameters under
writeToEnvironmentFiledirectly in your .yml file.Add
aadApp/updateunderprovision: Update your Microsoft Entra app with Microsoft Entra app manifest in step 1. For more information, see aadApp/update.Update
file/createOrUpdateJsonFile: Add the following environment variables when you debug locally:- ClientId: Microsoft Entra app client ID.
- ClientSecret: Microsoft Entra app client secret.
- OAuthAuthority: Microsoft Entra app oauth authority.
For more information, see file/updateJson.
In both the
m365agents.ymlfile and them365agents.local.ymlfile add the following code under theprovisionto create Microsoft Entra app.- uses: aadApp/create with: name: "YOUR_AAD_APP_NAME" generateClientSecret: true signInAudience: "AzureADMyOrg" 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_HOSTNote
Replace the value of "name" with your expected Microsoft Entra app name.
Add the following lines under
provisionto configure Microsoft Entra app with Microsoft Entra app template in the step 1.- uses: aadApp/update with: manifestPath: "YOUR_PATH_TO_AAD_APP_MANIFEST" outputFilePath : ./build/aad.manifest.${{TEAMSFX_ENV}}.jsonNote
Replace the value of
manifestPathwith the relative path of Microsoft Entra app manifest noted in step 1. For example:./aad.manifest.json
In the
m365agents.local.ymlfile:Add the following code under
provisionto add Microsoft Entra related configs to local debug service.Note
If the
file/createOrUpdateJsonFilesection is configured inm365agents.local.yml, then you can skip the following step.- uses: file/createOrUpdateJsonFile with: target: ./appsettings.Development.json appsettings: TeamsFx: Authentication: ClientId: ${{AAD_APP_CLIENT_ID}} ClientSecret: ${{SECRET_AAD_APP_CLIENT_SECRET}} InitiateLoginEndpoint: ${{TAB_ENDPOINT}}/auth-start.html OAuthAuthority: ${{AAD_APP_OAUTH_AUTHORITY}}
Update Infra Microsoft Entra related configs need to be configured in your remote service. The following example shows the configs on Azure Webapp.
- TeamsFx__Authentication__ClientId: Microsoft Entra app client ID.
- TeamsFx__Authentication__ClientSecret: Microsoft Entra app client secret.
- TeamsFx__Authentication__OAuthAuthority: Microsoft Entra app oauth authority.
Example for TeamsFx Tab template.
Open
infra/azure.parameters.jsonand add following lines intoparameters:"tabAadAppClientId": { "value": "${{AAD_APP_CLIENT_ID}}" }, "tabAadAppClientSecret": { "value": "${{SECRET_AAD_APP_CLIENT_SECRET}}" }, "tabAadAppOauthAuthorityHost": { "value": "${{AAD_APP_OAUTH_AUTHORITY_HOST}}" }, "tabAadAppTenantId": { "value": "${{AAD_APP_TENANT_ID}}" }Open the
infra/azure.bicepfile, find the code:param location string = resourceGroup().locationUpdate the code as:
param tabAadAppClientId string param tabAadAppOauthAuthorityHost string param tabAadAppTenantId string @secure() param tabAadAppClientSecret stringIn the
infra/azure.bicepfile, find the code:resource webApp 'Microsoft.Web/sites@2021-02-01' = { kind: 'app' location: location name: webAppName properties: { serverFarmId: serverfarm.id httpsOnly: true siteConfig: { appSettings: [ { name: 'WEBSITE_RUN_FROM_PACKAGE' value: '1' } ] ftpsState: 'FtpsOnly' } } }Update the code as:
resource webApp 'Microsoft.Web/sites@2021-02-01' = { kind: 'app' location: location name: webAppName properties: { serverFarmId: serverfarm.id httpsOnly: true siteConfig: { ftpsState: 'FtpsOnly' } } } resource webAppConfig 'Microsoft.Web/sites/config@2021-02-01' = { name: '${webAppName}/appsettings' properties: { WEBSITE_RUN_FROM_PACKAGE: '1' TeamsFx__Authentication__ClientId: tabAadAppClientId TeamsFx__Authentication__ClientSecret: tabAadAppClientSecret TeamsFx__Authentication__InitiateLoginEndpoint: 'https://${webApp.properties.defaultHostName}/auth-start.html' TeamsFx__Authentication__OAuthAuthority: uri(tabAadAppOauthAuthorityHost, tabAadAppTenantId) } }Update
appsettings.jsonandappsettings.Development.jsonfiles for Microsoft Entra related configs needs to be configured to your .NET project settings:TeamsFx: { Authentication: { ClientId: AAD app client id ClientSecret: AAD app client secret, InitiateLoginEndpoint: Login Endpoint, OAuthAuthority: AAD app oauth authority } }Note
You can use
$ENV_NAME$to reference envs in local/remote service.Example for TeamsFx Tab template.
Open
appsettings.jsonandappsettings.Development.jsonfiles, and update the code:"TeamsFx": { "Authentication": { "ClientId": "$clientId$", "ClientSecret": "$client-secret$", "InitiateLoginEndpoint": "$TAB_ENDPOINT$/auth-start.html", "OAuthAuthority": "$oauthAuthority$" } }Your environment is ready and you can update your code to add SSO to your Teams app. You can find samples:
- TeamsFx SDK: https://www.nuget.org/packages/Microsoft.TeamsFx/
- Sample Code: under
TeamsFx-Auth/Tab
Example for TeamsFx Tab template.
Create
Config.csand update the code as:using Microsoft.TeamsFx.Configuration; namespace {{YOUR_NAMESPACE}} { public class ConfigOptions { public TeamsFxOptions TeamsFx { get; set; } } public class TeamsFxOptions { public AuthenticationOptions Authentication { get; set; } } }Note
You need to replace
{{YOUR_NAMESPACE}}with your namespace name.Move the
TeamsFx-Auth/Tab/GetUserProfile.razorfile toComponents/.Add the
GetUserProfilecomponent to your razor page, for example:<h1>Hello, World</h1> <GetUserProfile />Open the
Program.csfile, find the code:builder.Services.AddScoped<MicrosoftTeams>();and update the code as:
var config = builder.Configuration.Get<ConfigOptions>(); builder.Services.AddTeamsFx(config.TeamsFx.Authentication); ```
Note
You need to exclude the sample code under the
TeamsFx-Authfile to avoid build failure by adding following code into the.csprojfile:<ItemGroup> <Compile Remove="TeamsFx-Auth/**/*" /> <None Include="TeamsFx-Auth/**/*" /> <Content Remove="TeamsFx-Auth/Tab/GetUserProfile.razor"/> </ItemGroup> ``` * Download `auth-start.html` and `auth-end.html` files from [GitHub Repo](https://github.com/OfficeDev/TeamsFx/tree/dev/templates/csharp/sso-tab/wwwroot) to `{ProjectDirectory}/wwwroot`.To check the SSO app works as expected, run the
Local Debugin Visual Studio.You can also run the app in cloud by selecting the
Provision in the cloudand thenDeploy to the cloud.
Teams bot application
Update Microsoft Entra app manifest in the
TeamsFx-Auth/aad.manifest.template.jsonfile.You can copy the file to any folder of your project, and rename as the
aad.manifest.jsonfile and note the path to this file for later reference. Make the following updates in the template to create or update a Microsoft Entra app for SSO.identifierUris: Used to uniquely identify and access the resource. You need to set correct Redirect URIs into "identifierUris" for successfully identify this app. For more information, see identifierUris attribute.
Example for TeamsFx Bot Template:
"identifierUris":[ "api://botid-${{BOT_ID}}" ]Note
You can use
${{ENV_NAME}}to reference variables in theenv/.env.{TEAMSFX_ENV}file.redirectUris: It lists registered redirect_uri values that Microsoft Entra ID accepts as destinations when returning tokens. You need to set necessary Redirect URIs into "redirectUris" for successfully returning token. For more information, see redirectUris attribute.
Example:
"web": { "redirectUris": [ "https://${{BOT_DOMAIN}}/bot-auth-end.html" ] }- "name": Replace the value with your expected Microsoft Entra app name.
Update app manifest.
- A
WebApplicationInfoobject needs to be added into your app manifest to enable SSO in the Teams app. For more information, see webApplicationInfo.
For example: open your app manifest template, and append the following object in app manifest:
"webApplicationInfo": { "id": "${{AAD_APP_CLIENT_ID}}", "resource": "SAME_AS_YOUR_IDENTIFIERURIS" }Note
You need to update the value of resource to your
identifierUrisconfigured in step 1.i, and use${{ENV_NAME}}to reference envs inenv/.env.{TEAMSFX_ENV}.Example for TeamsFx Bot template:
Open the
appPackage/manifest.jsonfile, and add the following property in the app manifest file:"webApplicationInfo": { "id": "${{AAD_APP_CLIENT_ID}}", "resource": "api://botid-${{BOT_ID}}" }- You can register your command under
commandsincommandListsof your bot:
{ "title": "YOUR_COMMAND_TITLE", "description": "YOUR_COMMAND_DESCRIPTION" }Example for TeamsFx Bot template:
{ "title": "show", "description": "Show user profile using Single Sign On feature" }Remember to delete the previous 'helloWorld' command since it isn't used.
- Also add bot domain to
validDomain:
"validDomains": [ "${{BOT_DOMAIN}}" ]- A
Update
m365agents.ymlandm365agents.local.ymlfiles: Microsoft Entra related changes and configs needs to be added into yourymlfiles:Add
aadApp/createunderprovisionfor creating new Microsoft Entra apps used for SSO. For more information, see available actions in Agents Toolkit.Note
You can add any missing parameters under
writeToEnvironmentFiledirectly in your .yml file.Add
aadApp/updateunderprovisionfor updating your Microsoft Entra app with Microsoft Entra app manifest in step 1. For more information, see aadApp/update.Update
file/createOrUpdateJsonFile for adding the following environment variables during local debug:- ClientId: Microsoft Entra app client ID.
- ClientSecret: Microsoft Entra app client secret.
- OAuthAuthority: Microsoft Entra app oauth authority. For more information, see file/updateJson.
Example for TeamsFx Bot template
In both
m365agents.ymlandm365agents.local.ymlfiles:Add the code under
provisionto create Microsoft Entra app.Note
If the
aadApp/createsection is missing underprovisionin your .yml file, you can copy and paste the required section into it.
- uses: aadApp/create with: name: "YOUR_AAD_APP_NAME" generateClientSecret: true signInAudience: "AzureADMyOrg" 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_HOSTNote
Replace the value of "name" with your expected Microsoft Entra app name.
Add the code under
provisionto configure Microsoft Entra app with Microsoft Entra app template in the step 1.- uses: aadApp/update with: manifestPath: "./aad.manifest.json" outputFilePath : ./build/aad.manifest.${{TEAMSFX_ENV}}.jsonNote
Replace the value of "manifestPath" with the relative path of Microsoft Entra app manifest noted in step 1. For example, './aad.manifest.json'
In the
m365agents.local.ymlfile:Update
file/createOrUpdateJsonFileunderprovisionto add Microsoft Entra related configs to local debug service.Note
If the
file/createOrUpdateJsonFilesection is configured inm365agents.local.yml, then you can skip the following step.- uses: file/createOrUpdateJsonFile with: target: ../ProjecName/appsettings.Development.json appsettings: BOT_ID: ${{BOT_ID}} BOT_PASSWORD: ${{SECRET_BOT_PASSWORD}} TeamsFx: Authentication: ClientId: ${{AAD_APP_CLIENT_ID}} ClientSecret: ${{SECRET_AAD_APP_CLIENT_SECRET}} OAuthAuthority: ${{AAD_APP_OAUTH_AUTHORITY}}/${{AAD_APP_TENANT_ID}} ApplicationIdUri: api://botid-${{BOT_ID}} Bot: InitiateLoginEndpoint: https://${{BOT_DOMAIN}}/bot-auth-start
Update Infra Microsoft Entra related configs to configure remote service. The following example shows the configs on Azure Webapp.
- TeamsFx__Authentication__ClientId: Microsoft Entra app client ID.
- TeamsFx__Authentication__ClientSecret: Microsoft Entra app client secret.
- TeamsFx__Authentication__OAuthAuthority: Microsoft Entra app oauth authority.
- TeamsFx__Authentication__Bot__InitiateLoginEndpoint: Auth start page for Bot.
- TeamsFx__Authentication__ApplicationIdUri: Microsoft Entra app identifies URIs.
Example for TeamsFx Bot template:
Open the
infra/azure.parameters.jsonfile, add the code toparameters:"m365ClientId": { "value": "${{AAD_APP_CLIENT_ID}}" }, "m365ClientSecret": { "value": "${{SECRET_AAD_APP_CLIENT_SECRET}}" }, "m365TenantId": { "value": "${{AAD_APP_TENANT_ID}}" }, "m365OauthAuthorityHost": { "value": "${{AAD_APP_OAUTH_AUTHORITY_HOST}}" }Open the
infra/azure.bicepfile and find the code:param location string = resourceGroup().locationUpdate the code as:
param location string = resourceGroup().location param m365ClientId string param m365TenantId string param m365OauthAuthorityHost string param m365ApplicationIdUri string = 'api://botid-${botAadAppClientId}' @secure() param m365ClientSecret stringAdd the code before output:
resource webAppSettings 'Microsoft.Web/sites/config@2021-02-01' = { name: '${webAppName}/appsettings' properties: { TeamsFx__Authentication__ClientId: m365ClientId TeamsFx__Authentication__ClientSecret: m365ClientSecret TeamsFx__Authentication__Bot__InitiateLoginEndpoint: uri('https://${webApp.properties.defaultHostName}', 'bot-auth-start') TeamsFx__Authentication__OAuthAuthority: uri(m365OauthAuthorityHost, m365TenantId) TeamsFx__Authentication__ApplicationIdUri: m365ApplicationIdUri BOT_ID: botAadAppClientId BOT_PASSWORD: botAadAppClientSecret RUNNING_ON_AZURE: '1' } }Note
If you want add additional configs to your Azure Webapp, add the configs in the webAppSettings.
Update the
appsettings.jsonfile and theappsettings.Development.jsonfile for Microsoft Entra related configs that needs to be configured to your .NET project settings:TeamsFx: { Authentication: { ClientId: AAD app client id ClientSecret: AAD app client secret, OAuthAuthority: AAD app oauth authority, ApplicationIdUri: AAD app identify uri, Bot: { InitiateLoginEndpoint: Auth start page for Bot } } }Note
You can use
$ENV_NAME$to reference envs in local/remote service.Example for TeamsFx Bot template:
Open
appsettings.jsonandappsettings.Development.jsonfiles, and add the code:"TeamsFx": { "Authentication": { "ClientId": "$clientId$", "ClientSecret": "$client-secret$", "OAuthAuthority": "$oauthAuthority$", "ApplicationIdUri": "$applicationIdUri$", "Bot": { "InitiateLoginEndpoint": "$initiateLoginEndpoint$" } } }Update your code to add SSO to your Teams app.
You can find samples code:
- TeamsFx SDK: https://www.nuget.org/packages/Microsoft.TeamsFx/
- Sample Code: under
TeamsFx-Auth/Bot
Example for TeamsFx Bot template:
- Open
Config.csand add following classes to the namespace:
using Microsoft.TeamsFx.Configuration; namespace {{YOUR_NAMESPACE}} { public class TeamsFxOptions { public AuthenticationOptions Authentication { get; set; } } public class ConfigOptions { public string BOT_ID { get; set; } public string BOT_PASSWORD { get; set; } public TeamsFxOptions TeamsFx { get; set; } } }Note
Replace the
{{YOUR_NAMESPACE}}property with your namespace name.Move
TeamsFx-Auth/Bot/SSOandTeamsFx-Auth/Bot/Pagesfiles to/.Note
Remember to replace
{{YOUR_NAMESPACE}}with your project namespace.Open the
Program.csfile, and find the code:
builder.Services.AddSingleton<BotFrameworkAuthentication, ConfigurationBotFrameworkAuthentication>();Update the code as:
builder.Services.AddRazorPages(); // Create the Bot Framework Adapter with error handling enabled. builder.Services.AddSingleton<IBotFrameworkHttpAdapter, AdapterWithErrorHandler>(); builder.Services.AddSingleton<IStorage, MemoryStorage>(); // Create the Conversation state. (Used by the Dialog system itself.) builder.Services.AddSingleton<ConversationState>(); // The Dialog that will be run by the bot. builder.Services.AddSingleton<SsoDialog>(); // Create the bot as a transient. In this case the ASP Controller is expecting an IBot. builder.Services.AddTransient<IBot, TeamsSsoBot<SsoDialog>>(); builder.Services.AddOptions<BotAuthenticationOptions>().Configure(options => { options.ClientId = config.TeamsFx.Authentication.ClientId; options.ClientSecret = config.TeamsFx.Authentication.ClientSecret; options.OAuthAuthority = config.TeamsFx.Authentication.OAuthAuthority; options.ApplicationIdUri = config.TeamsFx.Authentication.ApplicationIdUri; options.InitiateLoginEndpoint = config.TeamsFx.Authentication.Bot.InitiateLoginEndpoint; });Find the code:
builder.Services.AddSingleton<HelloWorldCommandHandler>(); builder.Services.AddSingleton(sp => { var options = new ConversationOptions() { Adapter = sp.GetService<CloudAdapter>(), Command = new CommandOptions() { Commands = new List<ITeamsCommandHandler> { sp.GetService<HelloWorldCommandHandler>() } } }; return new ConversationBot(options); });Update the code as:
builder.Services.AddSingleton(sp => { var options = new ConversationOptions() { Adapter = sp.GetService<CloudAdapter>(), Command = new CommandOptions() { Commands = new List<ITeamsCommandHandler> { } } }; return new ConversationBot(options); });Find and delete the code:
// Create the bot as a transient. In this case the ASP Controller is expecting an IBot. builder.Services.AddTransient<IBot, TeamsBot>();Find the code:
app.UseEndpoints(endpoints => { endpoints.MapControllers(); });Update the code as:
app.UseEndpoints(endpoints => { endpoints.MapControllers(); endpoints.MapRazorPages(); });Note
You need to exclude the sample code under
TeamsFx-Authto avoid build failure by adding the following code to.csprojfile:<ItemGroup> <Compile Remove="TeamsFx-Auth/**/*" /> <None Include="TeamsFx-Auth/**/*" /> <Content Remove="TeamsFx-Auth/Tab/GetUserProfile.razor"/> </ItemGroup>To check if SSO app works as expected, run the
Local Debugin Visual Studio.You can also run the app in cloud by selecting
Provision in the cloudand then selectDeploy to the cloudto update your app.
See also
Platform Docs