Use SSO authentication for bots
Single sign-on 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. Tabs and bots have similar flow for SSO support. But bot requests tokens and receives responses with a different protocol.
Note
OAuth 2.0 is an open standard for authentication and authorization used by Azure AD and many other identity providers. A basic understanding of OAuth 2.0 is a prerequisite for working with authentication in Teams.
See the following video to learn about single sign-on (SSO) support for bots:
Bot SSO at runtime
The following image illustrates the flow of SSO in bots:

The following steps help you with authentication and bot application tokens:
The bot sends a message to Teams with an OAuthCard that contains
tokenExchangeResourceto obtain an authentication token for the bot application. The user receives messages at all the active user endpoints.Note
- A user can have more than one active endpoint at a time.
- The bot token is received from every active user endpoint.
- The app must be installed in personal scope for SSO support.
If the current user is using your bot application for the first time, a request prompt appears to the user to do one of the following actions:
- Provide consent, if necessary.
- Handle step-up authentication, such as two-factor authentication.
Teams requests the bot application token from the Azure AD endpoint for the current user.
Azure AD sends the bot application token to the Teams application.
Teams sends the token to the bot as part of the value object returned by the invoking with sign in/tokenExchange.
The parsed token in the bot application provides the required information, such as the user's email address.
Develop an SSO Teams bot
The following steps guide you to develop SSO Teams bot:
- Register your app through the Azure AD portal.
- Update your Teams application manifest for your bot.
- Add the code to request and receive a bot token.
Register your app through the Azure AD portal
The steps to register your app through the Azure AD portal are similar to the tab SSO flow. The following steps guide you to register your app:
Register a new application in the Azure Active Directory – App Registrations portal.
Select New Registration. The Register an application page appears.

In the Register an application, do the following steps:
Note
The users are not asked for consent and are granted access tokens right away, if the Azure AD app is registered in the same tenant where they are making an authentication request in Teams. However, the users must provide consent to the permissions, if the Azure AD app is registered in a different tenant.
- Enter Name for your app.
- Select Supported account types, such as single tenant or multitenant.
- Select Register.

Go to overview page.
Copy the value of Application (client) ID.
Under Manage, go to Expose an API
Tip
To update your app manifest later, save the Application (client) ID value.
Important
- If you are building a standalone bot, enter the Application ID URI as
api://botid-{YourBotId}. Here YourBotId is your Azure AD application ID. - If you are building an app with a bot and a tab, enter the Application ID URI as
api://fully-qualified-domain-name.com/botid-{YourBotId}.
- If you are building a standalone bot, enter the Application ID URI as
Select Add a scope.
In the panel that prompts, enter
access_as_useras the Scope name.Note
The "access_as_user" scope used to add a client app is for "Administrators and users".
You must be aware of the following important restrictions:
- Only user-level Microsoft Graph API permissions, such as email, profile, offline_access, and OpenId are supported. If you need access to other Microsoft Graph scopes, such as
User.ReadorMail.Read, see Extend tab app with Microsoft Graph permissions and scope. - Your application's domain name must be same as the domain name that you have registered for your Azure AD application.
- Multiple domains per app are currently not supported.
- Applications that use the
azurewebsites.netdomain are not supported because it is common and may be a security risk.
- Only user-level Microsoft Graph API permissions, such as email, profile, offline_access, and OpenId are supported. If you need access to other Microsoft Graph scopes, such as
In the Who can consent?, enter Admins and users.
Enter the following details to configure the admin and user consent prompts with values that are appropriate for the
access_as_userscope.- Admin consent display name: Teams can access the user’s profile.
- Admin consent description: Teams can call the app’s web APIs as the current user.
- User consent display name: Teams can access your profile and make requests on your behalf.
- User consent description: Teams can call this app’s APIs with the same rights as you have.

Ensure that the state is set to Enabled.

Select Add scope to save the details. The domain part of the Scope name displayed must automatically match the Application ID URI set in the previous step, with
/access_as_userappended to the endapi://subdomain.example.com/00000000-0000-0000-0000-000000000000/access_as_user.In the Authorized client applications, identify the applications that you want to authorize for your app’s web application.
Select Add a client application.

Enter each of the following client IDs and select the authorized scope you created in the previous step:
1fec8e78-bce4-4aaf-ab1b-5451cc387264for Teams mobile or desktop application.5e3ce6c0-2b1f-4285-8d4b-75ee78787346for Teams web application.

Go to Authentication.
In Platform configurations, select Add a platform.

Select Web.

Enter the Redirect URIs for your app.
Note
This URI should be a fully qualified domain name. It's also followed by the API route where an authentication response is sent. If you're following any of the Teams samples, the URI is
https://token.botframework.com/.auth/web/redirect. For more information, see OAuth 2.0 authorization code flow.
The following steps will help you to enable implicit grant:
- Select Authentication from the left pane.
- Select the Access tokens and ID tokens checkboxes.

- Select Save to save the changes.
Add necessary API Permissions.
- Select API permissions from the left pane.
- Select Add a platform to add any permissions that your app requires to downstream APIs, for example, User.Read.
Update manifest in Microsoft Azure portal
The following steps will guide you to update the bot manifest in Azure portal:
Select Manifest from the left pane.
Ensure the config item is set to "accessTokenAcceptedVersion": 2. If not, change it's value to 2.

Note
If you are already in testing your bot in Teams, you must sign out from this app and sign out from Teams. Then sign in again to see this change.
Select Save.
Update the Azure portal with the OAuth connection
The following steps will guide you to update the Azure portal with the OAuth connection:
In the Azure portal, go to AzureBot
Go to Configuration on the left pane.
Select Add OAuth Connection Settings.

The following steps will guide you to complete the New Connection Setting form:
Note
Implicit grant may be required in the Azure AD application.
- Enter Name in the New Connection Setting page.
Note
The Name is referred to the settings of your bot service code in step 5 of Bot SSO at runtime.
- From the Service Provider drop-down, select Azure Active Directory v2.
- Enter the client credentials, such as Client Id and Client secret for the Azure AD application.
- For the Token Exchange URL, use the scope value defined in Update your Teams application manifest for your bot for example,
api://botid-<your-app-id>/. The Token Exchange URL indicates to the SDK that this Azure AD application is configured for SSO. - In the Tenant ID, enter common.
- Add all the Scopes configured when specifying permissions to downstream APIs for your Azure AD application. With the Client ID and Client secret provided, the token store exchanges the token for a graph token with defined permissions.
- Select Save.
- Select Apply.

Update your Teams application manifest for your bot
If the application contains a standalone bot, then use the following code to add new properties to the Teams application manifest:
"webApplicationInfo":
{
"id": "00000000-0000-0000-0000-000000000000",
"resource": "api://botid-00000000-0000-0000-0000-000000000000"
}
If the application contains a bot and a tab, then use the following code to add new properties to the Teams application manifest:
"webApplicationInfo":
{
"id": "00000000-0000-0000-0000-000000000000",
"resource": "api://subdomain.example.com/botid-00000000-0000-0000-0000-000000000000"
}
webApplicationInfo is the parent of the following elements:
- id - The client ID of the application. It's the application ID that you obtained as part of registering the application with Azure AD. Don't share this Application ID with multiple Teams apps. Create a new Azure AD app for each application manifest that uses
webApplicationInfo. - resource - The domain and subdomain of your application. It's the same URI, including the
api://protocol that you registered when creating yourscopein Register your app through the Azure AD portal. Don't include theaccess_as_userpath in your resource. The domain part of this URI must match the domain and subdomains used in the URLs of your Teams application manifest.
Add the code to request and receive a bot token
Request a bot token
The request to get the token is a normal POST message request using the existing message schema. It's included in the attachments of an OAuthCard. The schema for the OAuthCard class is defined in Microsoft Bot Schema 4.0 and it's similar to a sign in card. Teams treats this request as a silent token acquisition if the TokenExchangeResource property is populated on the card. For the Teams channel, only the Id property, which uniquely identifies a token request, is honored.
Note
The Microsoft Bot Framework OAuthPrompt or the MultiProviderAuthDialog is supported for SSO authentication.
If the user is using the application for the first time and user consent is required, the following dialog box appears to continue with the consent experience:

When the user selects Continue, the following events occur:
If the bot defines a sign in button, the sign in flow for bots is activated that is similar to the sign in flow from an OAuth card button in a message stream. The developer must decide which permissions require user's consent. This approach is recommended if you require a token with permissions beyond
openId. For example, if you want to exchange the token for graph resources.If the bot isn't providing a sign in button on the OAuth card, user consent is required for a minimal set of permissions. This token is useful for basic authentication and to get the user's email address.
C# token request without a sign in button
var attachment = new Attachment
{
Content = new OAuthCard
{
TokenExchangeResource = new TokenExchangeResource
{
Id = requestId
}
},
ContentType = OAuthCard.ContentType,
};
var activity = MessageFactory.Attachment(attachment);
// NOTE: This activity needs to be sent in the 1:1 conversation between the bot and the user.
// If the bot supports group and channel scope, this code should be updated to send the request to the 1:1 chat.
await turnContext.SendActivityAsync(activity, cancellationToken);
Receive the bot token
The response with the token is sent through an invoke activity with the same schema as other invoke activities that the bots receive today. The only difference is the invoke name, sign in/tokenExchange, and the value field. The value field contains the Id, a string of the initial request to get the token and the token field, a string value including the token.
Note
You might receive multiple responses for a given request if the user has multiple active endpoints. You must deduplicate the responses with the token.
C# code to handle the invoke activity
protected override async Task<InvokeResponse> OnInvokeActivityAsync
(ITurnContext<IInvokeActivity> turnContext, CancellationToken cancellationToken)
{
try
{
if (turnContext.Activity.Name == SignInConstants.TokenExchangeOperationName && turnContext.Activity.ChannelId == Channels.Msteams)
{
await OnTokenResponseEventAsync(turnContext, cancellationToken);
return new InvokeResponse() { Status = 200 };
}
else
{
return await base.OnInvokeActivityAsync(turnContext, cancellationToken);
}
}
catch (InvokeResponseException e)
{
return e.CreateInvokeResponse();
}
}
The turnContext.activity.value is of type TokenExchangeInvokeRequest and contains the token that can be further used by your bot. You must store the tokens for performance reasons and refresh them.
Token exchange failure
If there's a token exchange failure, use the following code:
{
"status": "<response code>",
"body":
{
"id":"<unique Id>",
"connectionName": "<connection Name on the bot (from the OAuth card)>",
"failureDetail": "<failure reason if status code is not 200, null otherwise>"
}
}
To understand what the bot does when the token exchange fails to trigger a consent prompt, see the following steps:
Note
No user action is required to be taken as the bot takes the actions when the token exchange fails.
The client starts a conversation with the bot triggering an OAuth scenario.
The bot sends back an OAuth card to the client.
The client intercepts the OAuth card before displaying it to the user and checks if it contains a
TokenExchangeResourceproperty.If the property exists, the client sends a
TokenExchangeInvokeRequestto the bot. The client must have an exchangeable token for the user, which must be an Azure AD v2 token and whose audience must be the same asTokenExchangeResource.Uriproperty. The client sends an invoke activity to the bot with the following code:{ "type": "Invoke", "name": "signin/tokenExchange", "value": { "id": "<any unique Id>", "connectionName": "<connection Name on the skill bot (from the OAuth card)>", "token": "<exchangeable token>" } }The bot processes the
TokenExchangeInvokeRequestand returns aTokenExchangeInvokeResponseback to the client. The client must wait until it receives theTokenExchangeInvokeResponse.{ "status": "<response code>", "body": { "id":"<unique Id>", "connectionName": "<connection Name on the skill bot (from the OAuth card)>", "failureDetail": "<failure reason if status code is not 200, null otherwise>" } }If the
TokenExchangeInvokeResponsehas astatusof200, then the client doesn't show the OAuth card. See the normal flow image. For any otherstatusor if theTokenExchangeInvokeResponseisn't received, then the client shows the OAuth card to the user. See the fallback flow image. If there are any errors or unmet dependencies like user consent, this activity ensures that the SSO flow falls back to normal OAuthCard flow.
Update the auth sample
Open Teams auth sample, and then complete the following steps to update it:
Update the TeamsBot to handle the deduping of the incoming request by including the following code:
protected override async Task OnSignInInvokeAsync(ITurnContext<IInvokeActivity> turnContext, CancellationToken cancellationToken) { await Dialog.RunAsync(turnContext, ConversationState.CreateProperty<DialogState>(nameof(DialogState)), cancellationToken); } protected override async Task OnTokenResponseEventAsync(ITurnContext<IEventActivity> turnContext, CancellationToken cancellationToken) { await Dialog.RunAsync(turnContext, ConversationState.CreateProperty<DialogState>(nameof(DialogState)), cancellationToken); }Update
appsettings.jsonto include thebotId, password, and the connection name defined in Update the Azure portal with the OAuth connection.Update the manifest and ensure that
token.botframework.comis in the valid domains list. For more information, see Teams auth sample.Zip the manifest with the profile images and install it in Teams.
Code sample
| Sample name | Description | .NET | C# | Node.js |
|---|---|---|---|---|
| Bot framework SDK | This sample code demonstrates how to get started with authentication in a bot for Microsoft Teams. | View | View | View |
Step-by-step guide
Follow the step-by-step guide, to build a bot with SSO authentication.
Feedback
Submit and view feedback for