Teams Tab App - MGT - TeamsFxProvider - When should an interactive login be required?

156 views Asked by At

I am creating a teams tab app which needs to call graph api on the users behalf, as such I am using the TeamsFxProvider in mgt to get the graph tokens using the logged in teams users details.

I initialise the app using app.initialize() then initially I was setting up the TeamsFxProvider like so:

const provider = new TeamsFxProvider(teamsUserCredential!, userScopes);
Providers.globalProvider = provider;
Providers.globalProvider.setState(ProviderState.SignedIn);

This is a react app so I am using useTeamsUserCredential to get the teams user credential.

This was working fine initially when testing in teams web however when I tested in the actual teams client I started getting issues where it was unable to get graph tokens because it needed user interaction. I refactored my code like this:

const provider = new TeamsFxProvider(teamsUserCredential!, userScopes);
Providers.globalProvider = provider;

// Attempt to get token silently
teamsUserCredential
    .getToken(userScopes)
    .then(() => Providers.globalProvider.setState(ProviderState.SignedIn))
    .catch(() => {
        // If silent token fails then try login popup
        teamsUserCredential.login(userScopes)
            .then(() => Providers.globalProvider.setState(ProviderState.SignedIn))
    })

And this now works as expected, in that if it can fetch a graph token silently, and if not it will create a pop up for the user to sign in, after which it works and then works silently from then on.

My question is, isn't the entire point of using the TeamsFxProvider that it uses the logged in teams users credentials to automatically get the graph token, without using a popup?

Am I doing something wrong or is this behaviour expected?

Why does this only happen in the teams desktop app, and not web?

2

There are 2 answers

0
QTom On BEST ANSWER

This is expected as confirmed by Prasad-MSFT in the comments.

For reference I'll put this here which shows an example project that does the same thing (tries to sign in silently and displays a login page if that fails): https://github.com/OfficeDev/TeamsFx-Samples/tree/v2.3.0/graph-toolkit-contact-exporter

0
SLdragon On

The behavior you observed is as expected. If getToken fails, you should prompt the user to log in, below is the example code:

  async checkIsConsentNeeded() {
    let consentNeeded = false;
    try {
      await this.credential.getToken(this.scope);
    } catch (error) {
      consentNeeded = true;
    }
    this.setState({
      showLoginPage: consentNeeded,
    });
    Providers.globalProvider.setState(
      consentNeeded ? ProviderState.SignedOut : ProviderState.SignedIn
    );
    return consentNeeded;
  }

  async loginBtnClick() {
    try {
      await this.credential.login(this.scope);
      Providers.globalProvider.setState(ProviderState.SignedIn);
      this.setState({
        showLoginPage: false,
      });
    } catch (err) {
      alert("Login failed: " + err);
      return;
    }
  }

In the browser you can silently get the token is due to cached access tokens in cookies or local storage.

By the way, for best practice, it is better to initiate the login process within a button click listener to prevent the browser from blocking the popup window.