A small interesting story about how the guys from Wrike integrated Microsoft Teams into their service and what it led to, as well as a big technical part about the integration process itself. By the way, they were one of the first in the world to do this on the day of the release of the chat.

1 + 1 = 3
In our experience at
Wrike , potential buyers, choosing a project management system, are increasingly interested in available integrations. In fact, from a pleasant bonus, the adaptation of the product to the existing ecosystem has become a factor that determines the choice of the client.
Of course, it is important for developers to focus on the most common tools for corporate users, and here Microsoft products are inevitable priority. However, it is even more important not to do integration for the sake of integration. 1 + 1 should give 3, in the sense that a bundle of solutions should create additional value for the client.
')
Therefore, we have consistently added integration with Azure Active Directory, OneDrive and Office 365 to our service. The ultimate goal of these steps is to create a seamless workspace where the user will not switch between applications and copy-paste information from one window to another every few minutes. tools and services for teamwork will not lie the abyss.
MS Teams has become a logical new step. 53% of companies employing 500+ employees use corporate instant messengers (
SpiceWorks data). We thought that it would be convenient for users discussing the work to immediately implement the results of the discussion. Therefore, together with Microsoft, the team selected the most appropriate service functions in such a situation and thought through their organic implementation in the Teams interface.
As a result, Wrike users can now create projects and tasks directly from the messenger, and any project can now be added to Teams as a new tab. Integration also supports making changes to the task (status, performer, deadline, comments) in parallel with the discussion.

The discussions of the project have become more substantive and accurate, due to the possibility to show a Gantt chart with deadlines inside the messenger, so it is in front of the eyes of the participants in the discussion.

And of course, an obvious opportunity was added - notifications for your tasks can now be received not only by email, but also by messages in Teams.
The development of this functionality took 2 months. During this time, the team has gained an interesting experience that may be useful for you.
On the technical side
Any tab application for Microsoft Teams consists of:
- an archive with a manifest in which the manifest.json file and resource files are located;
- external HTTP service that processes requests for pages: configuration, tab main page, deletion.
All pages are rendered inside the Microsoft Teams iframe. Examples of a manifest for a tab application are
described in MSDN . There you can also find
a manifest scheme . At the time of this writing, the actual version of the scheme was 0.4.
The main fields of the manifesto:
Id
- GUID, must be unique for different applications or different environments.Icons
- 44x44 and 88x88 resolution icons, each not more than 1.5 Kb.configUrl
- the URL that users will see first. It will start the application configuration.canUpdateConfig
is a sign of whether users can change the configuration of an already added application.needsIdentity
- allows you to get user information through Teams JS API.validDomains
- an array of trusted domains, which should be our domain. Wildcards are allowed.
After preparing the manifest and resources, the resulting archive can be
uploaded to Microsoft Teams .
Interaction with the infrastructure of Microsoft Teams is provided by the
Microsoft Teams JS API library . The library allows you to:
- run authorization flow through Azure Oauth2 or any other Oauth2 provider;
- Get current user information, channel identifiers, teams and groups in terms of the Azure Active Directory;
- get and save tab settings;
- set event handlers for events: saving settings, changing the theme, deleting a tab;
- create and copy to the clipboard the link to the object selected in the tab.
To use the library, it is necessary to connect it and initialize it on each page of the application:
<script src="https://statics.teams.microsoft.com/sdk/v0.4/js/MicrosoftTeams.min.js"></script> ... <script type="text/javascript"> microsoftTeams.initialize(); </script>
Consider an example application for MsTeams with a multi-page configuration and linking Azure AD and
Wrike accounts.
The specifics of the application in several iframes (configuration, tab) and with Oauth2 redirects require a sophisticated but typed flow for both the configuration and for displaying the application in a previously added tab.
Main processes:
- The user adds a new tab in Microsoft Teams.
- Unauthorized user comes to the previously added tab.
- An authorized user comes to the previously added tab.
The process of adding a tab is shown in the figure below. Microsoft Teams pages are marked in blue, pages of our application are in green, code and request processing actions are shown in white.

The “Welcome page” page displays basic information about our application and the “Connect” button, which starts the authorization flow in Azure AD.
Callback URL handler must:
- Request user information in Azure AD (for example, through the Microsoft Azure AD Graph API ).
- Decide what to do with the received information: create a new account in our system or use an existing one.
- "Log in" the user to our system, for example, issuing a session cookie.
- In case of successful authorization, the Callback URL page should simply close, since authorization starts in a new window, and Callback is the end point of authorization.
- In case of unsuccessful authorization, the Callback URL page can show the user the reason for the failure, for example, the user’s refusal to provide access, the lack of access to an Azure application, and so on.
The “Setup page” page is a settings page. It is requested when adding a tab and through the “Configuration” option in the menu of a previously added tab (if the manifest was set to
canUpdateConfig
).
Sample code to run Oauth2 authentication through a multi-tenant application in Azure AD (that is, the sample code for the Welcome page) looks like this:
<script src="https://statics.teams.microsoft.com/sdk/v0.4/js/MicrosoftTeams.min.js"></script> <input type="button" onclick="startAuth()" value="..."/> <script type="text/javascript"> microsoftTeams.initialize(); var startAuth = function() { microsoftTeams.authentication.authenticate({ url: 'https://login.windows.net/common/oauth2/authorize' + '?response_type=code%20id_token' + '&scope=openid' + '&response_mode=' + form_post + '&client_id=' + <YOUR_AZURE_APP_CLIENT_ID> + '&resource=https%3a%2f%2fgraph.windows.net' + '&nonce=' + <MS_NONCE> + '&state=' + <OAUTH2_STATE> + '&redirect_uri=' + encodeURIComponent('http://localhost/callback'), width: 700, height: 500, successCallback: onAuthSuccess, failureCallback: onAuthFailure }); }; var onAuthSuccess = function() { console.log('Auth success'); document.location.href='http://localhost/setup'; }; var onAuthFailure = function() { console.log('Auth failed'); microsoftTeams.settings.setValidityState(false); }; </script>
Options:
redirect_uri
- URL of the callback handler, in which GET request idToken will be passed. On it you will be able to get access token, refresh token and user information for linking an account from Azure AD to an account in our system.YOUR_AZURE_APP_CLIENT_ID
- application identifier.MS_NONCE
- randomly generated nonce, analogue of state for Azure Oauth2.OAUTH2_STATE
- Oauth2 state, which needs to be checked in the callback handler.
The launch of flow-authorization is provided by the
microsoftTeams.authenticate
method from Teams JS API. You do not need to explicitly call
window.open
. The
onAuthSuccess
,
onAuthFailure
are called in the context of the source page, from where the login window was opened.
A safer and more reliable timeout method to start
Oauth2 flow
involves a request to our handler, which will generate
OAUTH2_STATE
and redirect the user to
login.windows.net .
Detailed information on creating and configuring applications for Azure AD can be read
here .
An example of a code page “Setup page” for saving settings is shown below.
<script src="https://statics.teams.microsoft.com/sdk/v0.4/js/MicrosoftTeams.min.js"></script> <input id="name" type="text" placeholder="Enter your name" onkeyup="validate()"/> <script type="text/javascript"> microsoftTeams.initialize(); var isNameValid = function() { return jQuery('#name').val().trim().length > 0; } var validate = function() { </script>
Options:
contentUrl
- the address of the page that will be shown when the tab is opened;suggestedDisplayName
- tab name;websiteUrl
- the link opens from the Microsoft Teams menu.
The following code uses the following Teams JS API methods:
microsoftTeams.settings.setValidityState
- enable or disable the "Save" button;microsoftTeams.settings.registerOnSaveHandler
- event handler for saving settings;saveEvent.notifyFailure
, notifySuccess
- informs the Teams infrastructure about success or failure when saving settings;microsoftTeams.settings.setSettings
- saves tab settings.
Consider the process of user login to the previously added tab. Here are the following options:
- The user is new, not associated with our system.
- User known to our system, but not authorized.
- Authorized user.
We have “seamless” authorization, so we’ll just add a new user to our account in our system after logging in to Azure AD. This is the login process to the previously added tab.

Recall that the organizational structure inside Microsoft Teams is as follows:
- There can be many teams in a Teams account;
- there can be many channels in a command;
- There may be a lot of our tabs in the channel.
Tab settings and user information are available through
context
and
settings
(from Microsoft Teams JS API):
Challenges and Solutions
What difficulties can arise with such a structure?
The Wrike team decided that users will be authorized in Azure AD. User data:
upn
(user principal name or email),
teamId
,
channelId
are available through the JS API, but this data cannot be validated on the side on the backend side - only if the application in Azure AD requests rights that require admin permission. This is due to the feature of the Azure Graph API, according to which information about the structure of the organization is available only after the consent of the administrator. This approach is inconvenient because only a Azure AD admin can add a tab to a channel.
We do not know which tab the user opens, if there are several of them in the channel (we do not have a
tabId
, although we can generate it, but more on that below). Storage of custom settings is available only in
settings.customSetting
s, but access to
settings
not available from the tab pages, only from the configuration pages.
How to solve these problems? The collection of data on
teamId
,
channelId
,
tabId
can be organized during user authorization and stored on the side of our application. Requests from the user inside the tab can be validated based on data from the current context (
microsoftTeams.getContext
).
The tab identifier can be generated when adding, on the configuration page, for example, like this:
microsoftTeams.settings.registerOnSaveHandler(function (saveEvent) { microsoftTeams.settings.getSettings(function(settings) { var tabId = generateOrGetTabId(settings); var customSettings = { tabId: tabId }; microsoftTeams.settings.setSettings({ contentUrl: 'http://localhost/tabContent?tabId=' + tabId, ... customSettings: JSON.stringify(customSettings) }); saveEvent.notifySuccess(); }) });
There is no access to the
settings
tab in the code page, so we pass the parameters to the
query string
for
contentUrl
in the
query string
.
tabId
will
tabId
only when you first add a tab. When reconfiguring we will use the previously specified. It is responsible for
generateOrGetTabId
. The
settings.customSettings
field allows you to store the generated
tabId
both as a string and as a serialized JSON object.
In conclusion, I would like to tell you about
deepLinks
- a way to generate a link to a tab or to specific content within a tab.
At the time of this writing, there are two ways to generate links:
- Interactive - using
microsoftTeams.shareDeepLink
. The user is prompted for a name and the link is copied to the clipboard. Such links are recognized in the chat, rendered as text entered by the user, and lead to a tab with the specified entityId
and subEntityId
. A detailed description is here . - Non-interactive — by forming a link based on the application id (from the manifest), the context of the tab, and other parameters:
entityId
, subEntityId
and so on. Such links can be used for various notifications, for example, in email or messages from bots.
Description of how to form
deepLinks
is in
MSDN . Additionally, I would like to note that both methods work in the tabs page code, since they do not require the use of
microsoftTeams.settings
.
Teams JS API is actively developing, and in the development process, the version changed from 0.2 to 0.4. In addition, the manifest for bots and tabs has become common.
The Azure AD Graph API and the Microsoft Graph API were also used to integrate with Wrike. During the process and after the release, we had close communication with colleagues from Microsoft, and our feedback was taken into account.
Part of the wishes that the guys from Wrike voiced in the process of communication.- Team information must be available in the Teams JS API and / or in the Graph API.
- Access to the microsoftTeams.settings settings is needed in the tab, and not only on the settings page.
- There is a lack of tabId, although two types of Deep Links partially compensate for the lack of tabId.
- You need a more flexible scopes system for Graph Oauth2 authorization, which is necessary to get the list of members of the current team (team) without involving the Azure AD Tenant admin to customize the tab.
- More flexible configuration page settings for customizing styles, accessing native Microsoft Teams styles, and changing standard controls. Such settings will give more freedom to create Configuration Wizards.
Issues of access to the composition of the team are already solved in the
Bot API . Part of the functionality for Deep Links was published shortly before the release of Teams. Perhaps Teams support at the REST API level will be implemented in the Microsoft Graph API, as this API is being actively developed and involves interaction with various components of Office 365.
By the way, the form for sending a new application for review can be found
here . We hope that the Wrike experience will be useful to you, and Microsoft Teams users will be able to get even more useful tools for teamwork.
About the authors
Alexander Belyaev , product manager. Responsible for the elaboration of Job stories (within the framework of the Jobs to be Done concept) for the Wrike audience and, accordingly, for the functions that users use within the framework of typical scenarios of their work. It also develops the Wrike API and is responsible for integration with strategic partners. Loves cats and zen.
Oleg Vashenkov , backend developer. In the context of integration with Microsoft Teams, it is responsible for authorization, creation and integration of accounts, support and extension of the API for working within Teams. Loves mini hackathons - to implement ideas for new platforms and devices and try their solutions for work and life, as well as cars, including training, tuning and competitions.
We remind you that you can try Microsoft Azure for free here .