Single sign-on (SSO) support for tabs

Users sign in to Microsoft Teams through their work, school, or Microsoft account that is Office 365, Outlook, you can take the advantage by allowing a single sign on to authorize your Teams tab or task module on desktop or mobile clients. If a user sign in once, they don't have to sign in again on another device as they're signed in automatically. Also, your access token is prefetched to improve performance and load times.

Note

Teams mobile client versions supporting SSO

✔Teams for Android (1416/1.0.0.2020073101 and later)

✔Teams for iOS (Version: 2.0.18 and later)

✔Teams JavaScript SDK (Version: 1.11 and later) for SSO to work in meeting side panel.

For the best experience with Teams, use the latest version of iOS and Android.

Note

Quickstart

The simplest path to get started with tab SSO is with the Teams toolkit for Microsoft Visual Studio Code. For more information, see SSO with Teams toolkit and Visual Studio Code for tabs

How SSO works at runtime

The following image shows how the SSO process works:

Tab single sign-on SSO diagram
  1. In the tab, a JavaScript call is made to getAuthToken(). getAuthToken() tells Teams to obtain an access token for the tab application.
  2. If the current user is using your tab application for the first time, there's a request prompt to consent if consent is required. Alternately, there's a request prompt to handle step-up authentication such as two-factor authentication.
  3. Teams requests the tab access token from the Azure AD endpoint for the current user.
  4. Azure AD sends the tab access token to the Teams application.
  5. Teams sends the tab access token to the tab as part of the result object returned by the getAuthToken() call.
  6. The token is parsed in the tab application using JavaScript, to extract required information, such as the user's email address.

Note

The getAuthToken() is only valid for consenting to a limited set of user-level APIs that is email, profile, offline_access, and OpenId. It is not used for further Graph scopes such as User.Read or Mail.Read. For suggested workarounds, see Get an access token with Graph permissions.

The SSO API also works in task modules that embed web content.

Develop an SSO Microsoft Teams tab

This section describes the tasks involved in creating a Teams tab that uses SSO. These tasks are language- and framework-agnostic.

1. Create your Azure AD application

Note

There are some important restrictions that you must know:

  • Only user-level Graph API permissions are supported that is, email, profile, offline_access, OpenId. If you must have access to other Graph scopes such as User.Read or Mail.Read, see Get an access token with Graph permissions.
  • It is important that your application's domain name is the same as the domain name you have registered for your Azure AD application.
  • Currently multiple domains per app are not supported.
  • The user must set accessTokenAcceptedVersion to 2 for a new application.

To register your app through the Azure AD portal, follow these steps:

  1. Register a new application in the Azure AD App Registrations portal.

  2. Select New Registration. The Register an application page appears.

  3. In the Register an application page, enter the following values:

    1. Enter a Name for your app.
    2. Choose the Supported account types, select single tenant or multitenant account type. ¹
    • Leave Redirect URI empty.
    1. Choose Register.
  4. On the overview page, copy and save the Application (client) ID. You must have it later when updating your Teams application manifest.

  5. Under Manage, select Expose an API.

    Note

    • 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}.

    • Use lower case letters for domain name, don't use upper case. For example, to create an app service or web app, enter base resource name as demoapplication, then the URL will be https://demoapplication.azurewebsites.net. But if you use base resource name as DemoApplication, then the URL will be https://DemoApplication.azurewebsites.net and this supports in desktop, web, and iOS, but not in android.

  6. Select the Set link to generate the Application ID URI in the form of api://{AppID}. Insert your fully qualified domain name with a forward slash "/" appended to the end, between the double forward slashes and the GUID. The entire ID must have the form of api://fully-qualified-domain-name.com/{AppID}. ² For example, api://subdomain.example.com/00000000-0000-0000-0000-000000000000. The fully qualified domain name is the human readable domain name from which your app is served. If you're using a tunneling service such as ngrok, you must update this value whenever your ngrok subdomain changes.

  7. Select Add a scope. In the panel that opens, enter access_as_user as the Scope name.

  8. In the Who can consent? box, enter Admins and users.

  9. Enter the details in the boxes for configuring the admin and user consent prompts with values that are appropriate for the access_as_user scope:

    • Admin consent title: Teams can access the user’s profile.
    • Admin consent description: Teams can call the app’s web APIs as the current user.
    • User consent title: 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.
  10. Ensure that State is set to Enabled.

  11. Select Add scope to save the details. The domain part of the Scope name displayed below the text field must automatically match the Application ID URI set in the previous step, with /access_as_user appended to the end api://subdomain.example.com/00000000-0000-0000-0000-000000000000/access_as_user.

  12. In the Authorized client applications section, 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-5451cc387264 for Teams mobile or desktop application.
    • 5e3ce6c0-2b1f-4285-8d4b-75ee78787346 for Teams web application.
  13. Navigate to API Permissions. Select Add a permission > Microsoft Graph > Delegated permissions, then add the following permissions from Graph API:

    • User.Read enabled by default
    • email
    • offline_access
    • OpenId
    • profile
  14. Navigate to Authentication.

    Important

    If an app hasn't been granted IT admin consent, users have to provide consent the first time they use an app.

    To enter a redirect URI:

    • Select Add a platform.
    • Select web.
    • Enter the redirect URI for your app. This URI is the same fully qualified domain name that you entered in step 5. 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://subdomain.example.com/auth-end. For more information, see OAuth 2.0 authorization code flow.

    Note

    Implicit grant is not required for tab SSO.

Congratulations! You've completed the app registration prerequisites to continue with your tab SSO app.

Note

  • ¹ If your Azure AD app is registered in the same tenant where you are making an authentication request in Teams, the user cannot be asked to consent and is granted an access token right away. Users only consent to these permissions if the Azure AD app is registered in a different tenant.
  • ² If the custom domain is not added to Azure AD, you get an error stating that the host name must not be based on an already owned domain. To add custom domain to Azure AD and register it, follow the add a custom domain name to Azure AD procedure, and then repeat step 5. You can also get this error if you are not signed in with Admin credentials in the Office 365 tenancy.
  • If you are not receiving the user principal name (UPN) in the returned access token, you can add it as an optional claim in Azure AD.

2. Update your Teams application manifest

Use the following code to add new properties to your Teams manifest:

"webApplicationInfo": {
  "id": "00000000-0000-0000-0000-000000000000",
  "resource": "api://subdomain.example.com/00000000-0000-0000-0000-000000000000"
}
  • WebApplicationInfo is the parent of the following elements:
  • id - The client ID of the application. This is the application ID that you obtained as part of registering the application with Azure AD.
  • resource - The domain and subdomain of your application. This is the same URI (including the api:// protocol) that you registered when creating your scope in step 6. You must not include the access_as_user path in your resource. The domain part of this URI must match the domain, including any subdomains, used in the URLs of your Teams application manifest.

Note

  • The resource for an Azure AD app is usually the root of its site URL and the appID (e.g. api://subdomain.example.com/00000000-0000-0000-0000-000000000000). This value is also used to ensure your request is coming from the same domain. Ensure that the contentURL for your tab uses the same domains as your resource property.
  • You must use manifest version 1.5 or higher to implement the webApplicationInfo field.

3. Get an access token from your client-side code

Note

To avoid errors such as Teams SDK Error: resourceDisabled, ensure that Application ID URI is configured properly in Azure AD app registration and in your Teams app.

Use the following authentication API:

var authTokenRequest = {
  successCallback: function(result) { console.log("Success: " + result); },
  failureCallback: function(error) { console.log("Failure: " + error); }
};
microsoftTeams.authentication.getAuthToken(authTokenRequest);

When you call getAuthToken and user consent is required for user-level permissions, a dialog is shown to the user to grant consent.

After you receive access token in success callback, decode access token to view claims for that token. Optionally, manually copy and paste access token into a tool, such as jwt.ms. If you aren't receiving the UPN in the returned access token, add it as an optional claim in Azure AD. For more information, see access tokens.

Tab single sign-on SSO dialog prompt

Code snippets

The following code provides an example of on-behalf-of flow to fetch access token using MSAL library :


IConfidentialClientApplication app = ConfidentialClientApplicationBuilder.Create(<"Client id">)
                                                .WithClientSecret(<"Client secret">)
                                                .WithAuthority($"https://login.microsoftonline.com/<"Tenant id">")
                                                .Build();
 
            try
            {
                var idToken = <"Client side token">;
                UserAssertion assert = new UserAssertion(idToken);
                List<string> scopes = new List<string>();
                scopes.Add("https://graph.microsoft.com/User.Read");
                var responseToken = await app.AcquireTokenOnBehalfOf(scopes, assert).ExecuteAsync();
                return responseToken.AccessToken.ToString();
            }
            catch (Exception ex)
            {
                return ex.Message;
            }
        }

Code sample

Sample name Description C# Node.js
Tab SSO Microsoft Teams sample app for tabs Azure AD SSO View View,
Teams Toolkit

Known limitations

Get an access token with Graph permissions

Our current implementation for SSO only grants consent for user-level permissions that are not usable for making Graph calls. To get the permissions (scopes) needed to make a Graph call, SSO solutions must implement a custom web service to exchange the token received from the Teams JavaScript SDK for a token that includes the needed scopes. This is accomplished using Azure AD on-behalf-of flow.

A simple way of consenting on behalf of an organization as a tenant admin is to refer to https://login.microsoftonline.com/common/adminconsent?client_id=<AAD_App_ID>.

Another approach for getting Graph scopes is to present a consent dialog using our existing web-based Azure AD authentication approach. This approach involves popping up an Azure AD consent dialog box.

To ask for additional consent using the Auth API, follow these steps:

  1. The token retrieved using getAuthToken() must be exchanged server-side using Azure AD on-behalf-of flow to get access to those other Graph APIs. Ensure you use the v2 Graph endpoint for this exchange.
  2. If the exchange fails, Azure AD returns an invalid grant exception. There are usually one of two error messages, invalid_grant or interaction_required.
  3. When the exchange fails, you must ask for consent. Show some user interface (UI) asking the user to grant other consent. This UI must include a button that triggers an Azure AD consent dialog box using our Azure AD authentication API.
  4. When asking for more consent from Azure AD, you must include prompt=consent in your query-string-parameter to Azure AD, otherwise Azure AD doesn't ask for the other scopes.
    • Instead of ?scope={scopes}
    • Use this ?prompt=consent&scope={scopes}
    • Ensure that {scopes} includes all the scopes you're prompting the user for, for example, Mail.Read or User.Read.
  5. Once the user has granted more permission, retry the on-behalf-of-flow to get access to these other APIs.

Non-Azure AD authentication

The above-described authentication solution only works for apps and services that support Azure AD as an identity provider. Apps that want to authenticate using non-Azure AD based services must continue using the pop-up-based web authentication flow.

Note

SSO is supported for customer owned apps within the Azure AD B2C tenants.

Step-by-step guides

See also

Teams Bot with Single sign-on