Configure third party OAuth IdP authentication
Note
For authentication to work for your tab on mobile clients, ensure that you're using version 1.4.1 or later of the Microsoft Teams JavaScript client library (TeamsJS).
Your Microsoft Teams app might need to interact with various services, such as Facebook, Twitter, and Teams. Most of these services necessitate authentication and authorization for access. Teams stores user profile information in Microsoft Entra ID using Microsoft Graph. This article primarily focuses on using Microsoft Entra ID for authentication to access this information.
Microsoft Entra ID and numerous other service providers use OAuth 2.0, an open standard for authentication. It's essential to understand OAuth 2.0 when dealing with authentication in Teams and Microsoft Entra ID. The examples provided employ the OAuth 2.0 Implicit Grant flow, which retrieves the user's profile information from Microsoft Entra ID and Microsoft Graph.
The code in the article comes from the Teams sample app Microsoft Teams Authentication Sample (Node). It contains a static tab that requests an access token for Microsoft Graph, and shows the current user's basic profile information from Microsoft Entra ID.
For overview of authentication flow for tabs, see Authentication flow in tabs.
Authentication flow in tabs differs from authentication flow in bots.
Note
This topic reflects version 2.0.x of the Microsoft Teams JavaScript client library (TeamsJS). If you are using an earlier version, refer to the TeamsJS library overview for guidance on the differences between the latest TeamsJS and earlier versions.
Configure your app to use Microsoft Entra ID as an identity provider
OAuth 2.0 supporting identity providers don't authenticate requests from unregistered applications. Therefore, it's essential to register your applications in advance. For registering an application with Microsoft Entra ID, follow these steps:
Open the Application Registration Portal.
Select your app to view its properties, or select the "New Registration" button. Find the Redirect URI section for the app.
Select Web from the dropdown menu and update the URL to your authentication endpoint. In the TypeScript/Node.js and C# sample apps available on GitHub, the redirect URLs follow a similar pattern:
Redirect URLs:
https://<hostname>/bot-auth/simple-start
Replace <hostname>
with your actual host. This host can be a dedicated hosting site such as Azure, Glitch, or a ngrok tunnel to localhost on your development machine, such as abcd1234.ngrok.io
. If you don't have this information, ensure that you complete or host your app (or the sample app). Resume this process when you have this information.
Note
You can choose any third party OAuth provider, such as LinkedIn, Google, and others. The process to enable authentication for these providers is similar to using Microsoft Entra ID as a third party OAuth provider. For more information on using any third party OAuth provider, visit the website of the particular provider.
Initiate authentication flow
Note
If Experimental third-party storage partitioning is enabled, the third-party authentication fails. The app prompts for authentication repeatedly as the values aren’t stored locally.
Trigger the authentication flow by a user action. Avoid opening the authentication pop-up automatically, as this is likely to trigger the browser's pop-up blocker and confuse the user.
Add a button to your configuration or content page to enable the user to sign in when needed. This can be done in the tab configuration page or any content page.
Microsoft Entra ID, like most identity providers, doesn't allow its content to be placed in an iframe
. This means you need to add a page to host the identity provider that Teams client displays inside a pop-up window. In the following example, the page is /tab-auth/simple-start
. Use the authentication.authenticate()
function of the TeamsJS library to launch this page when the button is selected.
import { authentication } from "@microsoft/teams-js";
authentication.authenticate({
url: window.location.origin + "/tab-auth/simple-start-v2",
width: 600,
height: 535})
.then((result) => {
console.log("Login succeeded: " + result);
let data = localStorage.getItem(result);
localStorage.removeItem(result);
let tokenResult = JSON.parse(data);
showIdTokenAndClaims(tokenResult.idToken);
getUserProfile(tokenResult.accessToken);
})
.catch((reason) => {
console.log("Login failed: " + reason);
handleAuthError(reason);
});
Notes
The URL you pass to
authenticate()
is the start page of the authentication flow. In this example that is/tab-auth/simple-start
. This should match what you registered in the Microsoft Entra Application Registration Portal.Authentication flow must start on a page that's on your domain. This domain should also be listed in the
validDomains
section of the manifest. Failure to do results in an empty pop-up.If you fail to use
authenticate()
, the pop-up might not close at the end of the sign-in process, causing a problem.
Navigate to the authorization page from your pop-up page
When your pop-up page (/tab-auth/simple-start
) is displayed, the following code is run. The main goal of the page is to redirect to your identity provider so the user can sign-in. This redirection can be done on the server side using HTTP 302, but in this case it's done on the client side using a call to window.location.assign()
. This also allows app.getContext()
to be used to retrieve hinting information, which can be passed to Microsoft Entra ID.
app.getContext().then((context) => {
// Generate random state string and store it, so we can verify it in the callback
let state = _guid(); // _guid() is a helper function in the sample
localStorage.setItem("simple.state", state);
localStorage.removeItem("simple.error");
// Go to the Azure AD authorization endpoint
let queryParams = {
client_id: "{{appId}}",
response_type: "id_token token",
response_mode: "fragment",
scope: "https://graph.microsoft.com/User.Read openid",
redirect_uri: window.location.origin + "/tab/simple-end",
nonce: _guid(),
state: state,
// The context object is populated by Teams; the loginHint attribute
// is used as hinting information
login_hint: context.user.loginHint,
};
let authorizeEndpoint = `https://login.microsoftonline.com/${context.user.tenant.id}/oauth2/v2.0/authorize?${toQueryString(queryParams)}`;
window.location.assign(authorizeEndpoint);
});
After the user completes authorization, the user is redirected to the callback page you specified for your app at /tab-auth/simple-end
.
Notes
- See get user context information for help building authentication requests and URLs. For example, you can use the user's login name as the
login_hint
value for Microsoft Entra sign-in, which means the user might need to type less. Remember that you shouldn't use this context directly as proof of identity since an attacker could load your page in a malicious browser and provide it with any information they want. - Although the tab context provides useful information regarding the user, don't use this information to authenticate the user whether you get it as URL parameters to your tab content URL or by calling the
app.getContext()
function in the Microsoft Teams JavaScript client library (TeamsJS). A malicious actor could invoke your tab content URL with its own parameters, and a web page impersonating Microsoft Teams could load your tab content URL in an iframe and return its own data to thegetContext()
function. You should treat the identity-related information in the tab context simply as hints and validate them before use. - The
state
parameter is used to confirm that the service calling the callback URI is the service you called. If thestate
parameter in the callback doesn't match the parameter you sent during the call, then the return call isn't verified and should be terminated. - It isn't necessary to include the identity provider's domain in the
validDomains
list in the app's manifest.json file.
The callback page
In the last section, you called the Microsoft Entra authorization service and passed in user and app information so that Microsoft Entra ID could present the user with its own monolithic authorization experience. Your app has no control over what happens in this experience. All it knows is what is returned when Microsoft Entra ID calls the callback page that you provided (/tab-auth/simple-end
).
In this page, you need to determine success or failure based on the information returned by Microsoft Entra ID and call authentication.notifySuccess()
or authentication.notifyFailure()
. If the login was successful, you have access to service resources.
// Split the key-value pairs passed from Azure AD
// getHashParameters is a helper function that parses the arguments sent
// to the callback URL by Azure AD after the authorization call
let hashParams = getHashParameters();
if (hashParams["error"]) {
// Authentication/authorization failed
localStorage.setItem("simple.error", JSON.stringify(hashParams));
} else if (hashParams["access_token"]) {
// Get the stored state parameter and compare with incoming state
let expectedState = localStorage.getItem("simple.state");
if (expectedState !== hashParams["state"]) {
// State does not match, report error
localStorage.setItem("simple.error", JSON.stringify(hashParams));
authentication.notifyFailure("StateDoesNotMatch");
} else {
// Success -- return token information to the parent page.
// Use localStorage to avoid passing the token via notifySuccess; instead we send the item key.
let key = "simple.result";
localStorage.setItem(key, JSON.stringify({
idToken: hashParams["id_token"],
accessToken: hashParams["access_token"],
tokenType: hashParams["token_type"],
expiresIn: hashParams["expires_in"]
}));
authentication.notifySuccess(key);
}
} else {
// Unexpected condition: hash does not contain error or access_token parameter
localStorage.setItem("simple.error", JSON.stringify(hashParams));
authentication.notifyFailure("UnexpectedFailure");
}
This code parses the key-value pairs received from Microsoft Entra ID in window.location.hash
using the getHashParameters()
helper function. If it finds an access_token
, and the state
value is the same as the one provided at the start of the authentication flow, it returns the access token to the tab by calling notifySuccess()
; otherwise it reports an error with notifyFailure()
.
Notes
NotifyFailure()
has the following predefined failure reasons:
CancelledByUser
the user closed the pop-up window before completing the authentication flow.Note
We recommend not to use
same-origin
orsame-origin-allow-popups
values forCross-Origin-Opener-Policy
response header on the login pages, as it disrupts the connection to the parent window and causes the authenticate API call to return prematurely with aCancelledByUser
error.FailedToOpenWindow
the pop-up window couldn't be opened. When running Microsoft Teams in a browser, this typically means that a pop-up blocker has blocked the window.
If successful, you can refresh or reload the page and show content relevant to the now-authenticated user. If authentication fails, it displays an error message.
Your app can set its own session cookie so that the user doesn't need to sign in again when they return to your tab on the current device.
Note
- Chrome 80, scheduled for release in early 2020, introduces new cookie values and imposes cookie policies by default. It's recommended that you set the intended use for your cookies rather than rely on default browser behavior. See SameSite cookie attribute (2020 update).
- To obtain the appropriate token for Microsoft Teams Free and guest users, ensure your apps utilize the tenant-specific endpoint
https://login.microsoftonline.com/**{tenantId}**
. You can acquire the tenantId from the bot message or tab context. If your apps usehttps://login.microsoftonline.com/common
, users might receive incorrect tokens, causing them to log into the "home" tenant rather than the tenant they are signed into.
For more information on single sign-on (SSO), see the article Silent authentication.
Code sample
Sample code showing the tab authentication process using Microsoft Entra ID:
Sample name | Description | .NET | Node.js | Manifest |
---|---|---|---|---|
Tab SSO | This sample app shows Microsoft Entra SSO for tabs in Teams. | View | View, Teams Toolkit |
NA |
Tab, Bot, and Message Extension (ME) SSO | This sample shows SSO for Tab, Bot, and ME- search, action, link unfurl. | View | View | View |