Microsoft Teams and OAuth in Custom Tab

Custom Tabs provide developers with canvas to integrate their own user interface into Microsoft Teams. Developers have a lot of flexibility in what they load in the tab, but source domain(s) must be registered in the tab manifest. This is very similar to Office add-ins. In fact, you can think of tabs as Microsoft Teams version of an Office add-in. Like Office add-ins, there are some scenarios where source domains can be hard to predict. This is especially true in federated authentication scenarios. But like Office add-ins, Microsoft Teams offers a dialog API can be used to achieve complex authentication flows. In this post, I will illustrate how to use the Microsoft Teams authenticate dialog to perform an OAuth flow. I'll user Azure AD and the Microsoft Graph, but you could replace those with any identity provider/service.


Microsoft Teams Authentication Dialog

The Microsoft Teams Tab Library provides an authentication dialog for performing authentication flows. For a comprehensive explanation on why dialogs are necessary, you should review my older post on Connecting to Office 365 from an Office Add-in. You need a page or view to manage the authentication flow and pass the appropriate authentication results (ex: tokens) back to the tab via the Microsoft Teams Tab Library. The dialog can be launched by calling microsoftTeams.authentication.authenticate:

Launching authentication dialog

    url: "/app/auth.html",
    width: 400,
    height: 400,
    successCallback: function(token) {
        // Use access token to get some data from a service
    failureCallback: function(err) {
        document.getElementById("auth").innerText("Token failure.");

Passing information back to the tab is done by calling microsoftTeams.authentication.notifySuccess and microsoftTeams.authentication.notifyFailure. Here is an example of passing an access token back from the authentication dialog.

Passing information from dialog to tab

 authContext.acquireToken("", function(error, token) {
    if (error || !token)

As mentioned in the opening, my sample performs OAuth against Azure AD to call the Microsoft Graph. To do this, I leverage the Azure AD Authentication Library for JavaScript (adal.js). Here is my completed auth.html that is used in the authentication dialog.

Auth.html using adal.js

 <!DOCTYPE html>
<html lang="en">
    <meta charset="UTF-8">
    <script src=""></script>
    <script src=""></script>
    <script type="text/javascript">
    // Initialize microsoft teams tab library
    // Setup auth parameters for ADAL
    window.config = {
        instance: "",
        tenant: "common",
        clientId: "c6951c6d-dcaa-4e45-b4b8-2763c7916569",
        postLogoutRedirectUri: window.location.origin,
        cacheLocation: "localStorage",
        endpoints: {
            "": ""

    // Setup authcontext
    var authContext = new AuthenticationContext(window.config);
    if (authContext.isCallback(window.location.hash))
    else {
        // Check if user is cached
        var user = authContext.getCachedUser();
        if (!user)
            authContext.login(); // No cached user...force login
        else {
            authContext.acquireToken("", function(error, token) {
                if (error || !token) {
                    // TODO: this could cause infinite loop
                    // Should use microsoftTeams.authentication.notifyFailure after one try

I should note that Microsoft Teams offers a "silent" authentication option if Azure AD is the identity provider. This is only valid for scenarios where the existing Azure AD session cookies (from the user having already signed in to Microsoft Teams) will be sufficient for the custom tab. Any user consent, federation, or two-factor authentication constraints would require the dialog approach.


Integrating 3rd party identity and services into Microsoft Teams can deliver compelling scenarios to users. Hopefully this post illustrated how to achieve that with the Microsoft Teams Tab Library. You can find the official documentation on the authentication dialog here and the sample used in this post on GitHub: