Forum Discussion
Redirect Following Teams SSO Authentication
The primary error we’re encountering on machines that have multiple accounts configured is an error in the Auth/End process which is generating a client error “Refused to display 'https://login.microsoftonline.com/' in a frame because it set 'X-Frame-Options' to 'deny'” and failing to redirect to Home/Index when called on to do so (leaving the user on a blank Auth/End page). So far I’ve tried the following approaches to remedy the issue.
- Added an “X-Frame-Options” httpProtocol/customHeader to Web.config, with multiple tested value settings.
- Added an “Access-Control-Allow-Origin” customHeader to Web.config, with a value of “*”.
- Added an “Access-Control-Allow-Headers” customHeader to Web.config, with a value of “X-Requested-With.”
- Tested multiple login_hint values in the query parameters sent to the auth endpoint, derived from the Teams context (e.g. context.upn, context.username, context.userObjectId).
- Tried multiple approaches to the redirect command, from setting window.location.href to location.assign(), etc.
- Attempted to use an AJAX call to call a GET request to Home/Index as opposed to redirecting.
- Tried multiple authorization endpoints URI’s based on a handful of C# Teams SSO samples. Thus far, only https://login.microsoftonline.com/" + context.tid + "/oauth2/v2.0/authorize?" + toQueryString(queryParams) has worked to allow successful authentication.
- Tried multiple scope variations in the queryParams collection, currently passing User.Read and openid.
This is in addition to trying a number of different approaches in their entirety, such as using OWIN from a controller action and MSAL and MSAL v2.0. The three samples I’m currently focusing on are here: https://docs.microsoft.com/en-us/samples/browse/?products=office-teams&wt.mc_id=devcomteams_navsamples_webpage_mw&terms=SSO&languages=csharp, namely Teams Tab SSO Authentication, App SSO C#, and Tabs Azure AD Single Sign-On Sample.
- Meghana-MSFTMicrosoftWe are looking into this, we will update you.
- Meghana-MSFTMicrosoft
Jeremy_Messer - We see that the Tab SSO sample is working fine. Could you please let us know what extra code you have added or implemented? So that we can check it locally as well. Thanks.
- Jeremy_MesserCopper Contributor
Meghana-MSFT For full disclosure, this is our current AuthStart page/script:
<script src="../Scripts/msteams-sdk-1.6.0.js"></script> <script src="../Scripts/jquery-3.5.1.min.js"></script> <script type="text/javascript"> microsoftTeams.initialize(); microsoftTeams.getContext(function (context) { let state = _guid(); localStorage.setItem("auth.state", state); localStorage.removeItem("auth.error"); let queryParams = { client_id: "@ViewBag.ClientId", response_type: "id_token token", response_mode: "fragment", scope: "https://graph.microsoft.com/User.Read openid profile offline_access", redirect_uri: window.location.origin + "/auth/msteamsSilentEnd", nonce: _guid(), state: state, login_hint: context.loginHint, }; let authorizeEndpoint = `https://login.microsoftonline.com/${context.tid}/oauth2/v2.0/authorize?${toQueryString(queryParams)}`; window.location.assign(authorizeEndpoint); }); function toQueryString(queryParams) { let encodedQueryParams = []; for (let key in queryParams) { encodedQueryParams.push(key + "=" + encodeURIComponent(queryParams[key])); } return encodedQueryParams.join("&"); } function _decimalToHex(number) { var hex = number.toString(16); while (hex.length < 2) { hex = '0' + hex; } return hex; } function _guid() { var cryptoObj = window.crypto || window.msCrypto; if (cryptoObj && cryptoObj.getRandomValues) { var buffer = new Uint8Array(16); cryptoObj.getRandomValues(buffer); buffer[6] |= 0x40; buffer[6] &= 0x4f; buffer[8] |= 0x80; buffer[8] &= 0xbf; return _decimalToHex(buffer[0]) + _decimalToHex(buffer[1]) + _decimalToHex(buffer[2]) + _decimalToHex(buffer[3]) + '-' + _decimalToHex(buffer[4]) + _decimalToHex(buffer[5]) + '-' + _decimalToHex(buffer[6]) + _decimalToHex(buffer[7]) + '-' + _decimalToHex(buffer[8]) + _decimalToHex(buffer[9]) + '-' + _decimalToHex(buffer[10]) + _decimalToHex(buffer[11]) + _decimalToHex(buffer[12]) + _decimalToHex(buffer[13]) + _decimalToHex(buffer[14]) + _decimalToHex(buffer[15]); } else { var guidHolder = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'; var hex = '0123456789abcdef'; var r = 0; var guidResponse = ""; for (var i = 0; i < 36; i++) { if (guidHolder[i] !== '-' && guidHolder[i] !== '4') { r = Math.random() * 16 | 0; } if (guidHolder[i] === 'x') { guidResponse += hex[r]; } else if (guidHolder[i] === 'y') { r &= 0x3; r |= 0x8; guidResponse += hex[r]; } else { guidResponse += guidHolder[i]; } } return guidResponse; } } </script>
And this is the AuthEnd:
<script src="../Scripts/msteams-sdk-1.6.0.js"></script> <script src="../Scripts/jquery-3.5.1.min.js"></script> <script type="text/javascript"> microsoftTeams.initialize(); localStorage.removeItem("auth.error"); let hashParams = getHashParameters(); if (hashParams["error"]) { localStorage.setItem("auth.error", JSON.stringify(hashParams)); microsoftTeams.authentication.notifyFailure(hashParams["error"]); } else if (hashParams["access_token"]) { let expectedState = localStorage.getItem("auth.state"); if (expectedState !== hashParams["state"]) { localStorage.setItem("auth.error", JSON.stringify(hashParams)); microsoftTeams.authentication.notifyFailure("StateDoesNotMatch"); } else { let key = "auth.result"; localStorage.setItem(key, JSON.stringify({ idToken: hashParams["id_token"], accessToken: hashParams["access_token"], tokenType: hashParams["token_type"], expiresIn: hashParams["expires_in"] })); microsoftTeams.authentication.notifySuccess(key); window.location.href = "/Home/Index"; } } else { localStorage.setItem("auth.error", JSON.stringify(hashParams)); microsoftTeams.authentication.notifyFailure("UnexpectedFailure"); } function getHashParameters() { let hashParams = {}; location.hash.substr(1).split("&").forEach(function (item) { let s = item.split("="), k = s[0], v = s[1] && decodeURIComponent(s[1]); hashParams[k] = v; }); return hashParams; } </script>
Line #29 of the AuthEnd script is our culprit triggering the X-Frame issue on systems with multiple accounts.