0

I created a Teams tab application by customizing the SSO react app sample from the Teams toolkit. The application redirects the user to our website (inside one of the tabs). I can grab the id-token in react (teamsfx.getCredentials().getToken("")) and pass it to our web application via a query parameter.

This id-token is validated and then passed around to various microservices that comprise our backend.

This part works well, but then, we had the need to refresh the token. So, we decided for the web application (written in Angular) to fetch the token using @microsoft/teamsfx and @microsoft/teams-js npm packages.

While I am not certain if that is the way to go, when I execute the following code inside an angular service, it throws the "SDK initialization timed out" error.

    try {
      const teamsFx: TeamsFx = new TeamsFx(IdentityType.User, {         
        "clientId": "ee89fb47-a378-4096-b893-**********",
        "objectId": "df568fe9-3d33-4b22-94fc-**********",
        "oauth2PermissionScopeId": "4ce5bb24-585a-40d3-9891-************",
        "tenantId": "5d65ee67-1073-4979-884c-**************",
        "oauthHost": "https://login.microsoftonline.com",
        "oauthAuthority": "https://login.microsoftonline.com/5d65ee67-1073-4979-884c-****************",
        "applicationIdUris": "api://localhost/ee89fb47-a378-4096-b893-***************",
        "frontendEndpoint": "https://localhost",
        "initiateLoginEndpoint": "https://localhost:8101"
      });

      const creds = await teamsFx.getCredential().getToken('https://graph.microsoft.com/User.Read');
      const token = creds?.token;

      console.log("New Token: ", token);

      const expirationTimestamp = creds?.expiresOnTimestamp;
      this.scheduleRefresh(expirationTimestamp);
      this.tokenRefreshed.next({ token: token, expiresOnTimestamp: expirationTimestamp });
    }
    catch (error) {
      console.error("Error in getNewTeamsToken(): ", error);
    }

Am I missing anything here, or is the approach itself wrong? Please advise.

1 Answers1

0

Teams is basically just using MSAL under the covers (with a bit of other stuff thrown in I think) to get the token. If you want to be able to authenticate your user outside of Teams, in a separate web app, you can simply use MSAL yourself (something like this I'd guess: https://learn.microsoft.com/en-us/azure/active-directory/develop/tutorial-v2-angular-auth-code).

That would mean, essentially, that you have a tab web app, doing Teams SSO and then a separate standalone Angular app doing direct MSAL auth. Does you tab app actually do anything? If not, and you're only using it to redirect, you can instead combine these into a single app, and detect in the app whether you're in Teams or not - if you are, do SSO using TeamsFX. If not, do MSAL login directly. This link shows how to detect if your inside of Teams or not.

If you want to continue with separate apps that's fine, but I absolutely would not pass the token as a QueryString parameter - that is extremely dangerous. First of all, tokens are not meant to be passed like this at all, as they could be intercepted. Secondly, passing them on Querystring means that they are entirely open - anything inbetween can sniff the address and lift out your token (if it was a POST payload with httpS, for instance, at least the 'S' would be encrypting the token between browser and server).

Hilton Giesenow
  • 9,809
  • 2
  • 10
  • 24
  • Thank you so much for the reply! The link to find out whether you are inside teams or not really helps. While all your assertions about how to authenticate using MSAL are correct, what I would like the web app to do is that since I already obtained the token from teams, obtain refreshed token silently in the background from MS. The issue is that when I pass on the id_token (and, I accept that passing as query param is not safe at all), the app loads fine, but when I try to find out if a login has already been done using MSAL, it fails to recognize that! Am I making a mistake somewhere? – Manish Ballav Sep 01 '22 at 11:40
  • To answer your question, I would like to keep them as two separate apps as the web app is fully developed. Also, the teams app does nothing more than redirect. – Manish Ballav Sep 01 '22 at 11:41
  • I'm not sure how to answer more - I've not tried to get a refresh token in this way, and not tried passing it around for the very reason I mentioned. Basically, Teams is -giving- you the mechanism to handle this, but you're running into trouble by not implementing what MS is recommending. I also hear you about the app "being written", but if you're writing code -anyway- to get a "refresh" token, why not just do it properly, and get the -actual- token? – Hilton Giesenow Sep 01 '22 at 17:14
  • You are right about getting the actual token from MS using MSAL, but then that means that once redirected to our web app, the user has to once log in using his creds. I am trying to avoid that. That is why I passed the token from the react tab app. – Manish Ballav Sep 01 '22 at 18:22
  • You need to be clear on what "login" means here. If the user has no login session to M365 in their browser, then yes, they will need to login, via the account selector. That's different from the -consent- screen. To avoid the consent screen, either the consent in the Teams tab would work OR an admin can pre-consent the user. In either case, you should be able to get a token completely silently from within your web app. In that case you'd get a token properly, using MSAL, but it would be transparent to the user -unless- there's an issue (you need a fallback just in case). – Hilton Giesenow Sep 02 '22 at 05:14
  • Hilton Giesenow, I am accepting your answer as it explains a lot. We have decided to go with the react app refreshing the token and passing it to an HTTPS endpoint which will call the backend to replace the existing token. – Manish Ballav Sep 02 '22 at 18:14