-
Notifications
You must be signed in to change notification settings - Fork 192
Develop single sign on experience in Teams
Microsoft Teams provides a mechanism by which an application can obtain the signed-in Teams user token to access Microsoft Graph (and other APIs). Teams Toolkit facilitates this interaction by abstracting some of the Microsoft Entra flows and integrations behind some simple, high level APIs. This enables you to add single sign-on (SSO) features easily to your Teams application.
Basically you will need take care these configurations:
- In the Microsoft Entra app manifest file, you need to specify URIs such as the URI to identify the Microsoft Entra authentication app and the redirect URI for returning token.
- In the Teams manifest file, add the SSO application to link it with Teams application.
- In the Teams Toolkit configuration files and Infra files, you need to add necessary configurations to make SSO works for your Teams app.
- Add SSO application information in Teams Toolkit configuration files in order to make sure the authentication app can be registered on backend service and started by Teams Toolkit when you debug or preview Teams application.
In this tutorial you will learn:
Note: This sample will only provision single tenant Microsoft Entra app. For multi-tenant support, please refer to this wiki.
Note: You can find detail info about Microsoft Entra app manifest here.
Download Microsoft Entra app manifest template here to ./aad.manifest.json
. The Microsoft Entra manifest allows you to customize various aspects of your application registration. You can update the manifest as needed.
Note: You can find detail info about Teams app manifest here.
You can find your original Teams app manifest template in ./appPackages/manifest.json
, and you need to add webApplicationInfo
in the manifest.
webApplicationInfo
provides your Microsoft Entra App ID and Microsoft Graph information to help users seamlessly sign into your app.
Example: You can add following object into your Teams app manifest for your Tab project.
"webApplicationInfo": {
"id": "${{AAD_APP_CLIENT_ID}}",
"resource": "api://${{TAB_DOMAIN}}/${{AAD_APP_CLIENT_ID}}"
}
Note: You can use
${{ENV_NAME}}
to reference variables inenv/.env.{TEAMSFX_ENV}
.
You can find your Teams Toolkit configuration files (./teamsapp.yml
, ./teamsapp.local.yml
, etc.). Microsoft Entra related changes and configs needs to be added into your configuration files:
- add
aadApp/create
underprovision
:- For creating new Microsoft Entra apps used for SSO.
- You can find more info here
- add
aadApp/update
underprovision
- For updating your Microsoft Entra app with Microsoft Entra app manifest in step 1.
- You can find more info here
- for React project, update
cli/runNpmCommand
underdeploy
:- For adding following environment variables when local debug:
- REACT_APP_CLIENT_ID: Microsoft Entra app client id
- REACT_APP_START_LOGIN_PAGE_URL: Microsoft Entra app client secret
- For adding following environment variables when local debug:
- for React project, update
file/createOrUpdateEnvironmentFile
- For adding following environment variables when local debug:
- REACT_APP_CLIENT_ID: Microsoft Entra app client id
- REACT_APP_START_LOGIN_PAGE_URL: Login start page for authentication
- For adding following environment variables when local debug:
You can set following values if you are using TeamsFx Tab template.
Add following lines in provision
in teamsapp.yml
and teamsapp.local.yml
:
- 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_HOST
Note: Replace the value of "name" with your expected Microsoft Entra app name.
Add following lines in provision
in teamsapp.yml
and teamsapp.local.yml
:
- uses: aadApp/update
with:
manifestPath: "./aad.manifest.json"
outputFilePath: ./build/aad.manifest.${{TEAMSFX_ENV}}.json
Note: Replace the value of "manifestPath" with the relative path of Microsoft Entra app manifest template (
aad.manifest.json
) if you have modify the path of this file.
Note: For local you need to place
aad/update
afterfile/createOrUpdateEnvironmentFile
action sinceaad/update
will consume output offile/createOrUpdateEnvironmentFile
.
If you are building tab app with React framework, find cli/runNpmCommand
action with name build app
in teamsapp.yml
and add following env:
env:
REACT_APP_CLIENT_ID: ${{AAD_APP_CLIENT_ID}}
REACT_APP_START_LOGIN_PAGE_URL: ${{TAB_ENDPOINT}}/auth-start.html
If you are building tab app with React framework, find file/createOrUpdateEnvironmentFile
action for deploy in teamsapp.local.yml
and add following env:
envs:
...
REACT_APP_CLIENT_ID: ${{AAD_APP_CLIENT_ID}}
REACT_APP_START_LOGIN_PAGE_URL: ${{TAB_ENDPOINT}}/auth-start.html
With all changes above, your environment is ready and can update your code to add SSO to your Teams app.
For non-React tab app, following is a basic sample for getting SSO token with vanilla JavaScript.
function getSSOToken() {
return new Promise((resolve, reject) => {
microsoftTeams.authentication
.getAuthToken()
.then((token) => {
resolve(token);
})
.catch((error) => {
alert(error);
reject("Error getting token: " + error);
});
});
}
function getBasicUserInfo() {
getSSOToken().then((ssoToken) => {
const tokenObj = JSON.parse(window.atob(ssoToken.split(".")[1]));
console.log(`username: ${tokenObj.name}`);
console.log(`user email: ${tokenObj.preferred_username}`);
});
}
Suppose you are building your tab app with React framework. You can find and download sample code for TeamsFx Tab below to ./auth
:
You can follow the following steps to update your source code:
- Move
auth-start.html
andauth-end.html
inauth/public
folder topublic/
.
- These two HTML files are used for auth redirects.
- Move
sso
folder underauth/
tosrc/sso/
.
-
InitTeamsFx
: This file implements a function that initialize TeamsFx SDK and will openGetUserProfile
component after SDK is initialized. -
GetUserProfile
: This file implements a function that calls Microsoft Graph API to get user info.
- Import and add
InitTeamsFx
inWelcome.*
.
You can also find sample for SSO enabled Tab here.
Note: You can find detail info about Microsoft Entra app manifest here.
Download Microsoft Entra app manifest template here to ./aad.manifest.json
. The Microsoft Entra manifest allows you to customize various aspects of your application registration. You can update the manifest as needed.
Note: You can find detail info about Teams app manifest here.
You can find your original Teams app manifest template in ./appPackages/manifest.json
.
webApplicationInfo
provides your Microsoft Entra App ID and Microsoft Graph information to help users seamlessly sign into your app.
Example: You can add following object into your Teams app manifest for your Bot/Messaging Extension project.
"webApplicationInfo": {
"id": "${{AAD_APP_CLIENT_ID}}",
"resource": "api://botid-${{BOT_ID}}"
}
Note: You can use
${{ENV_NAME}}
to reference variables inenv/.env.{TEAMSFX_ENV}
.
commandLists
contains commands that your bot can recommend to users.
You can set following values if you are using TeamsFx Bot template.
{
"title": "profile",
"description": "Show user profile using Single Sign On feature"
}
validDomains
contains valid domains for websites the app expects to load within the Teams client.
You can set following values if you are using TeamsFx Bot template.
"validDomains": [
"${{BOT_DOMAIN}}"
]
You can find your Teams Toolkit configuration files (./teamsapp.yml
, ./teamsapp.local.yml
, etc.). Microsoft Entra related changes and configs needs to be added into your configuration files:
- add
aadApp/create
underprovision
:- For creating new Microsoft Entra apps used for SSO.
- You can find more info here
- add
aadApp/update
underprovision
- For updating your Microsoft Entra app with Microsoft Entra app manifest in step 1.
- You can find more info here
- update
file/createOrUpdateEnvironmentFile
- For adding following environment variables when local debug:
- M365_CLIENT_ID: Microsoft Entra app client id
- M365_CLIENT_SECRET: Microsoft Entra app client secret
- M365_TENANT_ID: Tenant id of Microsoft Entra app
- INITIATE_LOGIN_ENDPOINT: Login start page for authentication
- M365_AUTHORITY_HOST: Microsoft Entra app oauth authority host
- M365_APPLICATION_ID_URI: IdentifierUri for Microsoft Entra app
- For adding following environment variables when local debug:
You can set following values if you are using TeamsFx Tab/Bot template.
Add following lines in provision
in teamsapp.yml
and teamsapp.local.yml
:
- 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_HOST
Note: Replace the value of "name" with your expected Microsoft Entra app name.
Add following lines in provision
in teamsapp.yml
and teamsapp.local.yml
:
- uses: aadApp/update
with:
manifestPath: "./aad.manifest.json"
outputFilePath: ./build/aad.manifest.${{TEAMSFX_ENV}}.json
Note: Replace the value of "manifestPath" with the relative path of Microsoft Entra app manifest template (
aad.manifest.json
) if you have modify the path of this file.
Find file/createOrUpdateEnvironmentFile
action in teamsapp.local.yml
and add following env:
envs:
...
M365_CLIENT_ID: ${{AAD_APP_CLIENT_ID}}
M365_CLIENT_SECRET: ${{SECRET_AAD_APP_CLIENT_SECRET}}
M365_TENANT_ID: ${{AAD_APP_TENANT_ID}}
INITIATE_LOGIN_ENDPOINT: ${{BOT_ENDPOINT}}/auth-start.html
M365_AUTHORITY_HOST: ${{AAD_APP_OAUTH_AUTHORITY_HOST}}
M365_APPLICATION_ID_URI: api://botid-${{BOT_ID}}
Microsoft Entra related configs needs to be configured in your remote service. Following example shows the configs on Azure Webapp.
- M365_CLIENT_ID: Microsoft Entra app client id
- M365_CLIENT_SECRET: Microsoft Entra app client secret
- M365_TENANT_ID: Tenant id of Microsoft Entra app
- INITIATE_LOGIN_ENDPOINT: Login start page for authentication
- M365_AUTHORITY_HOST: Microsoft Entra app oauth authority host
- M365_APPLICATION_ID_URI: IdentifierUri for Microsoft Entra app
You can set follow the steps below if you are using TeamsFx Tab/Bot template.
- Open
infra/azure.parameters.json
and add following lines intoparameters
:
"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
infra/azure.bicep
find follow line:
param location string = resourceGroup().location
and add following lines:
param m365ClientId string
param m365TenantId string
param m365OauthAuthorityHost string
param m365ApplicationIdUri string = 'api://botid-${botAadAppClientId}'
@secure()
param m365ClientSecret string
- Add following lines before output
resource webAppSettings 'Microsoft.Web/sites/config@2021-02-01' = {
name: '${webAppName}/appsettings'
properties: {
M365_CLIENT_ID: m365ClientId
M365_CLIENT_SECRET: m365ClientSecret
INITIATE_LOGIN_ENDPOINT: uri('https://${webApp.properties.defaultHostName}', 'auth-start.html')
M365_AUTHORITY_HOST: m365OauthAuthorityHost
M365_TENANT_ID: m365TenantId
M365_APPLICATION_ID_URI: m365ApplicationIdUri
BOT_ID: botAadAppClientId
BOT_PASSWORD: botAadAppClientSecret
RUNNING_ON_AZURE: '1'
}
}
Note: If you want add additional configs to your Azure Webapp, please add the configs in the webAppSettings.
Note: You may also need to specify default node version by adding the following config:
WEBSITE_NODE_DEFAULT_VERSION: '14.20.0'
You can find and download sample code for TeamsFx Tab below to ./auth
:
Note: The following part is sample code for
Chat Command
bot. SSO forChat Command
bot only supports personal chat. This bot may not work if you add it to a team or a group chat.
-
Move files under
auth/sso
folder tosrc
. ProfileSsoCommandHandler class is a sso command handler to get user info with SSO token. You can follow this method and create your own sso command handler. -
Move
auth/public
folder tosrc/public
. This folder contains HTML pages that the bot application hosts. When single sign-on flows are initiated with Microsoft Entra, Microsoft Entra will redirect the user to these pages. -
Execute the following commands under
./
folder:npm install isomorphic-fetch --save
-
(For ts only) Execute the following commands under
./
folder:npm install copyfiles --save-dev
and replace following line in package.json:"build": "tsc --build && shx cp -r ./src/adaptiveCards ./lib/src",
with:
"build": "tsc --build && shx cp -r ./src/adaptiveCards ./lib/src && copyfiles src/public/*.html lib/",
By doing this, the HTML pages used for auth redirect will be copied when building this bot project.
-
In
src/index
file, you need to add following line to importisomorphic-fetch
:
require("isomorphic-fetch");
and add following lines to add redirect to auth pages:
import path from "path";
import send from "send";
expressApp.get(["/auth-start.html", "/auth-end.html"], async (req, res) => {
send(
req,
path.join(
__dirname,
"public",
req.url.includes("auth-start.html") ? "auth-start.html" : "auth-end.html"
)
).pipe(res);
});
and update commandApp.requestHandler to make auth works:
await commandApp.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;
}
});
- Add
ssoConfig
andssoCommands
inConversationBot
insrc/internal/initialize
:
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()],
},
});
Implement the Key API handleMessageExtensionQueryWithSSO
in TeamsActivityHandler.handleTeamsMessagingExtensionQuery
. Read this Wiki for more detail about the API handleMessageExtensionQueryWithSSO
To make this work in your application:
- Move the
auth/public
folder tosrc/public
. This folder contains HTML pages that the bot application hosts. When single sign-on flows are initiated with Microsoft Entra, Microsoft Entra will redirect the user to these pages. - Modify your
src/index
to add the appropriateexpress
routes to these pages.
const path = require("path");
const send = require("send");
// Listen for incoming requests.
expressApp.post("/api/messages", async (req, res) => {
await adapter
.process(req, res, async (context) => {
await bot.run(context);
})
.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;
}
});
});
expressApp.get(["/auth-start.html", "/auth-end.html"], async (req, res) => {
send(
req,
path.join(
__dirname,
"public",
req.url.includes("auth-start.html") ? "auth-start.html" : "auth-end.html"
)
).pipe(res);
});
- Execute the following commands under
./
folder:npm install @microsoft/teamsfx
- Execute the following commands under
./
folder:npm install isomorphic-fetch
- Implement the key API
handleMessageExtensionQueryWithSSO
inTeamsActivityHandler.handleTeamsMessagingExtensionQuery
- (For ts only) Install
copyfiles
npm packages in your bot project, add or update thebuild
script insrc/package.json
as following
"build": "tsc --build && copyfiles ./public/*.html lib/",
By doing this, the HTML pages used for auth redirect will be copied when building this bot project.
- Update
templates/appPackage/aad.template.json
your scopes which used inhandleMessageExtensionQueryWithSSO
.
"requiredResourceAccess": [
{
"resourceAppId": "Microsoft Graph",
"resourceAccess": [
{
"id": "User.Read",
"type": "Scope"
}
]
}
]
You can debug your application by pressing F5.
Teams Toolkit will use the Microsoft Entra manifest file to register a Microsoft Entra application registered for SSO.
To learn more about Teams Toolkit local debug functionalities, refer to this document.
The Microsoft Entra manifest allows you to customize various aspects of your application registration. You can update the manifest as needed.
Follow this document if you need to include additional API permissions to access your desired APIs.
Follow this document to view your Microsoft Entra application in Azure Portal.
Build Custom Engine Copilots
- Build a basic AI chatbot for Teams
- Build an AI agent chatbot for Teams
- Expand AI bot's knowledge with your content
Scenario-based Tutorials
- Send notifications to Teams
- Respond to chat commands in Teams
- Respond to card actions in Teams
- Embed a dashboard canvas in Teams
Extend your app across Microsoft 365
- Teams tabs in Microsoft 365 and Outlook
- Teams message extension for Outlook
- Add Outlook Add-in to a Teams app
App settings and Microsoft Entra Apps
- Manage Application settings with Teams Toolkit
- Manage Microsoft Entra Application Registration with Teams Toolkit
- Use an existing Microsoft Entra app
- Use a multi-tenant Microsoft Entra app
Configure multiple capabilities
- How to configure Tab capability within your Teams app
- How to configure Bot capability within your Teams app
- How to configure Message Extension capability within your Teams app
Add Authentication to your app
- How to add single sign on in Teams Toolkit for Visual Studio Code
- How to enable Single Sign-on in Teams Toolkit for Visual Studio
Connect to cloud resources
- How to integrate Azure Functions with your Teams app
- How to integrate Azure API Management
- Integrate with Azure SQL Database
- Integrate with Azure Key Vault
Deploy apps to production