cancel
Showing results for 
Search instead for 
Did you mean: 
Reply
Anonymous
Not applicable

How to configure SSO on a intranet page (SharePoint)

Hi,

 

I have been trying to configure SSO on our organization SharePoint website using PVA. But I don't see it to be working. I have been referring to the below URLs:

 

SSO doc 

https://docs.microsoft.com/en-us/power-virtual-agents/configure-sso#:~:text=Power%20Virtual%20Agents....

 

GitHub Sample code doc

https://github.com/microsoft/PowerVirtualAgentsSamples/blob/master/BuildYourOwnCanvasSamples/3.singl...


I have created a HTML file adding the SSO code provided from the above doc and published in the SharePoint website. I do not wish to see the login sign in card which asks to pass the token rather I need to Sign-in directly once I click the Chatbot button.

 

pva1.png

 

I have also posted regarding the same in the past as well. But no luck. Any help is much appreciated. 

 

Regards,

Hemanth

1 ACCEPTED SOLUTION

Accepted Solutions
aksridhar1
Advocate II
Advocate II

Hi @Anonymous 

 

Not sure if you are still facing issue with SSO working. I have got this issue fixed on my end and would like to share some inputs on that

 

1) I have seen the behavior of SSO and login that shows up in PVA bot is not consistent among browsers. Also you may be aware that the login status is stored in local stroage/session as specified in the MSAL.

 

2) I also saw that the code in github had issues related to how userId is passed. The particular line that was causing this login to come was this one below:

 

var userID = clientApplication.account!=null && clientApplication.account.accountIdentifier != null ?
("<Prefix>" + clientApplication.account.accountIdentifier).substr(0, 64) :
(Math.random().toString() + Date.now().toString()).substr(0, 64); // Make sure this will not exceed 64 characters

 

The userID is being used in the webchat to pass the UserID and this is supposed to be the User Id from AAD which is not the case with the <Prefix>. I fixed this to pass just the Id and no prefix.

 

var userID = clientApplication.account!=null && clientApplication.account.accountIdentifier != null ?
clientApplication.account.accountIdentifier:
(Math.random().toString() + Date.now().toString()).substr(0, 64); // Make sure this will not exceed 64 characters

 

This should take care of passing right UserID

 

if (action.type === 'DIRECT_LINE/CONNECT_FULFILLED')
{
/*
dispatch({
type: 'WEB_CHAT/SEND_EVENT',
payload: {
name: 'startConversation',
type: 'event',
value: {
text: "Hello"
}
}
});
return next(action);
*/
}

 

This is the code that is causing the Login to appear always. One more fix which I did in my case is to force the user login to happen before the webchat is displayed. This will make sure that the user token is created when webchat is initialized and what I have noticed is that after the below MSAL js changes, I never see a Login box in the chat.

 

if (!clientApplication)
{
clientApplication = new Msal.UserAgentApplication(msalConfig);
clientApplication.handleRedirectCallback(authRedirectCallBack);

//Below code will silently try to get token without popup. If there is no login already exists it will throw exception.
//As 2nd step, Login will be forced using LoginRedirect method
var newRequest =
{
scopes: ["user.read", 'openid', 'profile'],
}

clientApplication.acquireTokenSilent(newRequest).then(function(response)
{
//Now get the user display name
let user = clientApplication.getAccount();
document.getElementById("divUser").style.display="block";
document.getElementById("userName").innerHTML = " " + user.name;
}
).catch(function (error)
{
document.getElementById("divUser").style.display="block";
//Now get the user display name
document.getElementById("userName").innerHTML = "Not Logged in";
$('#divPopup').modal({backdrop: 'static',keyboard: false});
setTimeout(function()
{
//Now redirect to URI so that token will be created
clientApplication.loginRedirect(newRequest);

}, 2000);
});
}

 

The above code is trying to get token silently and if that fails it just forces login using redirect. This will make sure that first time user logs in, it will force token to be created and then it will be stored in local storage.

 

After this fix, my bot works fine all the time in the external web page. Hope this helps. Do not hesitate to ask any further questions.

View solution in original post

26 REPLIES 26
aksridhar1
Advocate II
Advocate II

Hi @Anonymous 

 

Not sure if you are still facing issue with SSO working. I have got this issue fixed on my end and would like to share some inputs on that

 

1) I have seen the behavior of SSO and login that shows up in PVA bot is not consistent among browsers. Also you may be aware that the login status is stored in local stroage/session as specified in the MSAL.

 

2) I also saw that the code in github had issues related to how userId is passed. The particular line that was causing this login to come was this one below:

 

var userID = clientApplication.account!=null && clientApplication.account.accountIdentifier != null ?
("<Prefix>" + clientApplication.account.accountIdentifier).substr(0, 64) :
(Math.random().toString() + Date.now().toString()).substr(0, 64); // Make sure this will not exceed 64 characters

 

The userID is being used in the webchat to pass the UserID and this is supposed to be the User Id from AAD which is not the case with the <Prefix>. I fixed this to pass just the Id and no prefix.

 

var userID = clientApplication.account!=null && clientApplication.account.accountIdentifier != null ?
clientApplication.account.accountIdentifier:
(Math.random().toString() + Date.now().toString()).substr(0, 64); // Make sure this will not exceed 64 characters

 

This should take care of passing right UserID

 

if (action.type === 'DIRECT_LINE/CONNECT_FULFILLED')
{
/*
dispatch({
type: 'WEB_CHAT/SEND_EVENT',
payload: {
name: 'startConversation',
type: 'event',
value: {
text: "Hello"
}
}
});
return next(action);
*/
}

 

This is the code that is causing the Login to appear always. One more fix which I did in my case is to force the user login to happen before the webchat is displayed. This will make sure that the user token is created when webchat is initialized and what I have noticed is that after the below MSAL js changes, I never see a Login box in the chat.

 

if (!clientApplication)
{
clientApplication = new Msal.UserAgentApplication(msalConfig);
clientApplication.handleRedirectCallback(authRedirectCallBack);

//Below code will silently try to get token without popup. If there is no login already exists it will throw exception.
//As 2nd step, Login will be forced using LoginRedirect method
var newRequest =
{
scopes: ["user.read", 'openid', 'profile'],
}

clientApplication.acquireTokenSilent(newRequest).then(function(response)
{
//Now get the user display name
let user = clientApplication.getAccount();
document.getElementById("divUser").style.display="block";
document.getElementById("userName").innerHTML = " " + user.name;
}
).catch(function (error)
{
document.getElementById("divUser").style.display="block";
//Now get the user display name
document.getElementById("userName").innerHTML = "Not Logged in";
$('#divPopup').modal({backdrop: 'static',keyboard: false});
setTimeout(function()
{
//Now redirect to URI so that token will be created
clientApplication.loginRedirect(newRequest);

}, 2000);
});
}

 

The above code is trying to get token silently and if that fails it just forces login using redirect. This will make sure that first time user logs in, it will force token to be created and then it will be stored in local storage.

 

After this fix, my bot works fine all the time in the external web page. Hope this helps. Do not hesitate to ask any further questions.

Anonymous
Not applicable

Hi @aksridhar1 

 

Thanks a lot for responding back..

 

Yes, I still face issues with SSO. Below is the code that I am using to achieve SSO. I have added the changes that was told by you to my code. I do not want to use the login button since I have already logged into my SharePoint website.

 

<!DOCTYPE html>
<html>
  <head>
    <title>Virtual Agent</title>
    <script src="https://cdn.botframework.com/botframework-webchat/latest/webchat.js"></script>

    <script
      type="text/javascript"
      src="https://alcdn.msauth.net/lib/1.2.0/js/msal.js"></script>

    <script
      src="https://unpkg.com/@azure/storage-blob@10.3.0/browser/azure-storage.blob.min.js"
      integrity="sha384-fsfhtLyVQo3L3Bh73qgQoRR328xEeXnRGdoi53kjo1uectCfAHFfavrBBN2Nkbdf"
      crossorigin="anonymous"></script>

    <script type="text/javascript">
      if (typeof Msal === "undefined")
        document.write(
          unescape(
            "%3Cscript src='https://alcdn.msftauth.net/lib/1.2.0/js/msal.js' type='text/javascript' %3E%3C/script%3E"
          )
        );
    </script>

    <style>
      html,
      body {
        height: 100%;
      }

      body {
        margin: 0;
      }

      .modal {
        display: none; /* Hidden by default */
        position: fixed; /* Stay in place */
        z-index: 1; /* Sit on top */
        padding-top: 100px; /* Location of the box */
        left: 0;
        top: 0;
        width: 100%; /* Full width */
        height: 100%; /* Full height */
        overflow: auto; /* Enable scroll if needed */
        background-color: rgb(0, 0, 0); /* Fallback color */
        background-color: rgba(0, 0, 0, 0.4); /* Black w/ opacity */
      }

      .modal-content {
        background-color: #fefefe;
        margin: auto;
        padding: 10px;
        border: 1px solid #888;
        width: 500px;
        height: 575px;
      }
      .close {
        color: black;
        float: right;
        font-size: 28px;
        font-weight: bold;
      }

      .close:hover,
      .close:focus {
        color: #000;
        text-decoration: none;
        cursor: pointer;
      }

      .main {
        margin: 18px;
        border-radius: 4px;
      }

      div[role="form"] {
        background-color: #3392ff;
      }

      #webchat {
        position: center;
        height: 530px;
        width: 100%;
        top: 60px;
        overflow: hidden;
      }
      #heading {
        padding-bottom: 5px;
      }

      h1 {
        font-size: 14px;
        font-family: Segoe UI;
        font-style: normal;
        font-weight: 600;
        font-size: 14px;
        line-height: 20px;
        color: #f3f2f1;
        letter-spacing: 0.005em;
        display: table-cell;
        vertical-align: middle;
        padding: 13px 0px 0px 20px;
      }

      #login {
        position: fixed;
        margin-left: 150px;
      }

      .span {
        font-weight: bold;
      }
      #myBtn {
        position: fixed;
        float: right;
        outline: none;
        width: 60px;
        height: 80px;
        margin: auto auto auto 10px;
      }
      button:hover {
        background-color: transparent;
      }
    </style>
  </head>
  <body>

    <button id="myBtn" type="button">Power Virtual Agent</button>

    <button id="login" name="login" onclick="onSignInClick()" style="background-color: aliceblue">Log In</button>

    <div id="myModal" class="modal">

      <div class="modal-content" style="background-color: #ffd933">

        <span class="close">&times;</span>
        <div id="chatwindow">
          <div id="heading">
            <span class="span"><strong>Virtual Agent</strong></span>
            <label id="divUser" name="divUser" style="width: 75%; height: 15px; border-color: Transparent"></label>
            <label id="userName" name="userName" style="width: 75%; height: 15px; border-color: Transparent">Not logged in.</label>
          </div>
          <div id="webchat"></div>
        </div>
      </div>
    </div>

    <script>

      var modal = document.getElementById("myModal");
      var btn = document.getElementById("myBtn");
      var span = document.getElementsByClassName("close")[0];
      btn.onclick = function () {
        modal.style.display = "block";
      };
      span.onclick = function () {
        modal.style.display = "none";
      };
      window.onclick = function (event) {
        if (event.target == modal) {
          modal.style.display = "none";
        }
      };

    </script>

    <script>
      function onSignin(idToken) {
        let user = clientApplication.getAccount();
        alert("User: " + JSON.stringify(user));

        document.getElementById("userName").innerHTML = "Currently logged in as " + user.name;
        let requestObj1 = {
          scopes: ["user.read", "openid", "profile"],
        };
      }

      function onSignInClick() {
        let user = clientApplication.getAccount();
        let requestObj = {
          scopes: ["user.read", "openid", "profile"],
        };

        clientApplication.loginPopup(requestObj).then(onSignin).catch(function (error) {
            console.log("error: " + error);
          });
      }

      function getOAuthCardResourceUri(activity) {
        if (
          activity &&
          activity.attachments &&
          activity.attachments[0] &&
          activity.attachments[0].contentType === "application/vnd.microsoft.card.oauth" &&
          activity.attachments[0].content.tokenExchangeResource)
          {
          return activity.attachments[0].content.tokenExchangeResource.uri;
          }
      }

      function exchangeTokenAsync(resourceUri) {
        let user = clientApplication.getAccount();

        if (user) {
          console.log("User exist " + JSON.stringify(user));

          let requestObj = {
            scopes: [resourceUri],
          };
          console.log("RequestObj: " + JSON.stringify(requestObj));

          return clientApplication.acquireTokenSilent(requestObj).then(function (tokenResponse) {
              console.log("ExchangeTokenAsync requestObj: " + tokenResponse.accessToken);
              return tokenResponse.accessToken;
            })
            .catch(function (error) {
              console.log("ExchangeTokenAsync error: " + error);
            });
        } else {
          return Promise.resolve(null);
        }
      }

      async function fetchJSON(url, options = {}) {
        const res = await fetch(url, {
          ...options,
          headers: {
            ...options.headers,
            accept: "application/json",
          },
        });

        if (!res.ok) {
          throw new Error(`Failed to fetch JSON due to ${res.status}`);
        }

        return await res.json();
      }
    </script>

    <script>
      var clientApplication;

      (function () {
        var msalConfig = {
          auth: {
            clientId: "<Removed Canvas Client ID>",
            authority:"https://login.microsoftonline.com/<Removed Directory ID>",
          },
          cache: {
            cacheLocation: "localStorage",
            storeAuthStateInCookie: false,
          },
        };
        if (!clientApplication) {
          clientApplication = new Msal.UserAgentApplication(msalConfig);

          // I get an error stating "Uncaught ReferenceError: authRedirectCallBack is not defined"
          clientApplication.handleRedirectCallback(authRedirectCallBack);

          //Below code will silently try to get token without popup. If there is no login already exists it will throw exception.
          //As 2nd step, Login will be forced using LoginRedirect method
          var newRequest = {
            scopes: ["user.read", "openid", "profile"],
          };

          clientApplication.acquireTokenSilent(newRequest).then(function (response)
          {
              //Now get the user display name
              let user = clientApplication.getAccount();
              document.getElementById("divUser").style.display = "block";
              document.getElementById("userName").innerHTML = " " + user.name;
          })
          .catch(function (error)
          {
              document.getElementById("divUser").style.display = "block";
              //Now get the user display name
              document.getElementById("userName").innerHTML = "Not Logged in";
              $("#divPopup").modal({ backdrop: "static", keyboard: false });
              setTimeout(function ()
              {
                //Now redirect to URI so that token will be created
                clientApplication.loginRedirect(newRequest);
              }, 2000);
          });
        }
      })();

      (async function main() {

        var BOT_ID = "<Removed BOT ID>";
        var theURL = "https://powerva.microsoft.com/api/botmanagement/v1/directline/directlinetoken?botId=" + BOT_ID;

        var userId = clientApplication.account!=null && clientApplication.account.accountIdentifier != null ? clientApplication.account.accountIdentifier: (Math.random().toString() + Date.now().toString()).substr(0, 64); // Make sure this will not exceed 64 characters

        console.log("Async function main userId: " + userId);

        const { token } = await fetchJSON(theURL);
        const directLine = window.WebChat.createDirectLine({ token });
        const store = WebChat.createStore(
          {},
          ({ dispatch }) => (next) => (action) => {
            const { type } = action;
            if (action.type === "DIRECT_LINE/CONNECT_FULFILLED")
            {

              /*dispatch({
                type: "WEB_CHAT/SEND_EVENT",
                payload: {
                  name: "startConversation",
                  type: "event",
                  value: { text: "hello" },
                },
              });
              return next(action);*/

            }
            if (action.type === "DIRECT_LINE/INCOMING_ACTIVITY")
            {
              const activity = action.payload.activity;
              let resourceUri;
              if (activity.from && activity.from.role === "bot" &&(resourceUri = getOAuthCardResourceUri(activity)))
              {
                exchangeTokenAsync(resourceUri).then(function (token) {
                  if (token) {
                    directLine.postActivity({
                        type: "invoke",
                        name: "signin/tokenExchange",
                        value: {
                          id:activity.attachments[0].content.tokenExchangeResource.id,
                          connectionName:activity.attachments[0].content.connectionName,
                          token,
                        },
                        from: {
                          id: userId,
                          name: clientApplication.account.name,
                          role: "user",
                        },
                      }).subscribe((id) => {

                          console.log("id: " + id);

                          if (id === "retry")
                          {
                            console.log(`Bot was not able to handle the invoke, so display the oauthCard`);
                            return next(action);
                          }
                          console.log(`Else: tokenexchange successful and we do not display the oauthCard`);
                        },
                        (error) => {
                          console.log(`An error occurred to display the oauthCard`);
                          return next(action);
                        }
                      );
                    return;
                  } else return next(action);
                });
              } else return next(action);
            } else return next(action);
          }
        );

        const styleOptions = {
          // Add styleOptions to customize Web Chat canvas
       	 hideUploadButton: true
        };

        window.WebChat.renderWebChat(
          {
            directLine: directLine,
            store,
            userID: userId,
            styleOptions,
          },
          document.getElementById("webchat")
        );
      })().catch((err) => console.error("An error occurred: " + err));
    </script>
  </body>
</html>

 

I am getting an error stating

"Uncaught ReferenceError: authRedirectCallBack is not defined"  from the below line of code.
clientApplication.handleRedirectCallback(authRedirectCallBack);

 

So I just created a function

 

function authRedirectCallBack(error, response) {
if (error) {
console.log(error);
}
}
 
And I saw my name to be displayed on the label tag on the bot screen as below.
a1.jpg
 

I also see the below error as well

webchat.js:2 POST https://directline.botframework.com/v3/directline/conversations/6EES0CsPuThCYcqw3AK1Cb-6/activities 502

 

It always entry into the id === "retry" block of code.

 

if (id === "retry")
{
console.log(`Bot was not able to handle the invoke, so display the oauthCard`);
return next(action);
}

 

I still get the login box when I start to chat with my bot. 

 

Can you please help me solve this. Thanks.

aksridhar1
Advocate II
Advocate II

@Anonymous ,

 

With this approach, the redirect URL needs to be passed

 

var msalConfig = 
	{
		auth: 
		{
	    	clientId: '', //Client Id of the AAD Aopp
	   		authority: 'https://login.microsoftonline.com/<TenantId>', //Login
	    	redirectUri: "<SharePoint Page where Bot will be hosted>", //URL that MSAL will redirect to when token is created
	    	navigateToLoginRequestUrl: false //Flag whether to navigate to page if token is not found
		},
	   	cache: 
	   	{
	     cacheLocation: 'localStorage', //Where to store the token information - Local storage
	     storeAuthStateInCookie: false //Whether to store auth information in cookie
	   	}
	};


if (!clientApplication) 
{
		clientApplication = new Msal.UserAgentApplication(msalConfig);
		clientApplication.handleRedirectCallback(authRedirectCallBack);	
}

function authRedirectCallBack(error, response) 
{
    //Do Nothing Here since we don't come back to this page.
    
}

Also make sure to add the redirect url of the SharePoint page where the bot is hosted in AAD App redirect Uri otherwise you will receive a error. 

 

Also can you check your AAD App settings to make sure the configuration is correct. Make sure to add your redirect uri.

 

Hope this helps.

Anonymous
Not applicable

@aksridhar1 

 

Thank you, I have done the code changes as above. But no luck. I still see the login card.


Below is the code section of MSAL and the main method.

<script>
      var clientApplication;

      (function () {
        var msalConfig =
	       {
		     auth:
		          {
	    	         clientId: '<Have removed the Client ID>', //Client Id of the AAD Aopp
	   		         authority: 'https://login.microsoftonline.com/<Have removed the Directory ID>', //Login
	    	         redirectUri: "https://<org name>.sharepoint.com/sites/testing/MT/project/SitePages/Home.aspx", //URL that MSAL will redirect to when token is created
	    	         navigateToLoginRequestUrl: false //Flag whether to navigate to page if token is not found
		          },
	   	  cache:
	   	        {
	               cacheLocation: 'localStorage', //Where to store the token information - Local storage
	               storeAuthStateInCookie: false //Whether to store auth information in cookie
	   	        }
	       };

             if (!clientApplication)
             {
		             clientApplication = new Msal.UserAgentApplication(msalConfig);
		             clientApplication.handleRedirectCallback(authRedirectCallBack);
             }

      function authRedirectCallBack(error, response)
      {
        //Do Nothing Here since we don't come back to this page.

      }


          //Below code will silently try to get token without popup. If there is no login already exists it will throw exception.
          //As 2nd step, Login will be forced using LoginRedirect method
          var newRequest = {
            scopes: ["user.read", "openid", "profile"],
          };

          clientApplication.acquireTokenSilent(newRequest).then(function (response)
          {
              //Now get the user display name
              let user = clientApplication.getAccount();
              document.getElementById("divUser").style.display = "block";
              document.getElementById("userName").innerHTML = " " + user.name;
          })
          .catch(function (error)
          {
              document.getElementById("divUser").style.display = "block";
              //Now get the user display name
              document.getElementById("userName").innerHTML = "Not Logged in";
              $("#divPopup").modal({ backdrop: "static", keyboard: false });
              setTimeout(function ()
              {
                //Now redirect to URI so that token will be created
                clientApplication.loginRedirect(newRequest);
              }, 2000);
          });
      })();

      (async function main() {

        var BOT_ID = "<Have removed the Bot ID>";
        var theURL = "https://powerva.microsoft.com/api/botmanagement/v1/directline/directlinetoken?botId=" + BOT_ID;

        var userId = clientApplication.account!=null && clientApplication.account.accountIdentifier != null ? clientApplication.account.accountIdentifier: (Math.random().toString() + Date.now().toString()).substr(0, 64); // Make sure this will not exceed 64 characters

        console.log("Async function main userId: " + userId);

        const { token } = await fetchJSON(theURL);
        const directLine = window.WebChat.createDirectLine({ token });
        const store = WebChat.createStore(
          {},
          ({ dispatch }) => (next) => (action) => {
            const { type } = action;
            if (action.type === "DIRECT_LINE/CONNECT_FULFILLED")
            {
              /*
              dispatch({
                type: "WEB_CHAT/SEND_EVENT",
                payload: {
                  name: "startConversation",
                  type: "event",
                  value: { text: "hello" },
                },
              });
              return next(action);
              */
            }
            if (action.type === "DIRECT_LINE/INCOMING_ACTIVITY")
            {
              const activity = action.payload.activity;
              let resourceUri;
              if (activity.from && activity.from.role === "bot" &&(resourceUri = getOAuthCardResourceUri(activity)))
              {
                exchangeTokenAsync(resourceUri).then(function (token) {
                  if (token) {
                    directLine.postActivity({
                        type: "invoke",
                        name: "signin/tokenExchange",
                        value: {
                          id:activity.attachments[0].content.tokenExchangeResource.id,
                          connectionName:activity.attachments[0].content.connectionName,
                          token,
                        },
                        from: {
                          id: userId,
                          name: clientApplication.account.name,
                          role: "user",
                        },
                      }).subscribe((id) => {

                          console.log("id: " + id);

                          if (id === "retry")
                          {
                            console.log(`Bot was not able to handle the invoke, so display the oauthCard`);
                            return next(action);
                          }
                          console.log(`Else: tokenexchange successful and we do not display the oauthCard`);
                        },
                        (error) => {
                          console.log(`An error occurred to display the oauthCard`);
                          return next(action);
                        }
                      );
                    return;
                  } else return next(action);
                });
              } else return next(action);
            } else return next(action);
          }
        );

        const styleOptions = {
          // Add styleOptions to customize Web Chat canvas
       	 hideUploadButton: true
        };

        window.WebChat.renderWebChat(
          {
            directLine: directLine,
            store,
            userID: userId,
            styleOptions,
          },
          document.getElementById("webchat")
        );
      })().catch((err) => console.error("An error occurred: " + err));
    </script>

 

Below is code section of all functions

  <script>
      function onSignin(idToken) {
        let user = clientApplication.getAccount();
        alert("User: " + JSON.stringify(user));

        document.getElementById("userName").innerHTML = "Currently logged in as " + user.name;
        let requestObj1 = {
          scopes: ["user.read", "openid", "profile"],
        };
      }

      function onSignInClick() {
        let user = clientApplication.getAccount();
        let requestObj = {
          scopes: ["user.read", "openid", "profile"],
        };

        clientApplication.loginPopup(requestObj).then(onSignin).catch(function (error) {
            console.log("error: " + error);
          });
      }

      function getOAuthCardResourceUri(activity) {
        if (
          activity &&
          activity.attachments &&
          activity.attachments[0] &&
          activity.attachments[0].contentType === "application/vnd.microsoft.card.oauth" &&
          activity.attachments[0].content.tokenExchangeResource)
          {
          return activity.attachments[0].content.tokenExchangeResource.uri;
          }
      }

      function exchangeTokenAsync(resourceUri) {
        let user = clientApplication.getAccount();

        if (user) {
          console.log("User exist " + JSON.stringify(user));

          let requestObj = {
            scopes: [resourceUri],
          };
          console.log("RequestObj: " + JSON.stringify(requestObj));

          return clientApplication.acquireTokenSilent(requestObj).then(function (tokenResponse) {
              console.log("ExchangeTokenAsync requestObj: " + tokenResponse.accessToken);
              return tokenResponse.accessToken;
            })
            .catch(function (error) {
              console.log("ExchangeTokenAsync error: " + error);
            });
        } else {
          return Promise.resolve(null);
        }
      }

      async function fetchJSON(url, options = {}) {
        const res = await fetch(url, {
          ...options,
          headers: {
            ...options.headers,
            accept: "application/json",
          },
        });

        if (!res.ok) {
          throw new Error(`Failed to fetch JSON due to ${res.status}`);
        }

        return await res.json();
      }
    </script>


I have added the SharePoint redirect uri in the code and on the AAD app as well.

The SSO configuration in Azure AD are done as per the doc provided by Microsoft.

 

Azure Canvas/SSO App registration

azure2.jpg

 

Azure Authentication App registration

azure3.jpg

 

In the console I see the below error

 

POST https://directline.botframework.com/v3/directline/conversations/52jH6J9MMCFFFk77eFTDHO-f/activities 502

 

And as the id is "retry" it enters into the if block of (id==='retry') so the login card always shows up.

aksridhar1
Advocate II
Advocate II

I rally have not seen this error. This certainly means the bot is not able to communicate may be due to token exchange issue. Can you verify your bot token exchange url and make sure it is update in AAD app as well as PVA settings? Also the error 502 means some kind of user error. Can you try to step through the code and put a breakpoint to see what part f the code is failing. As the user tries to talk to bot, the request and response changes. Check that out

Anonymous
Not applicable

@aksridhar1 

I did try to add break points and try to check which step is failing, But I am not able to figure which step fails from the code, as per the below snapshot I could see my name being passed but the end I still see the login card on by chatbot.

 

code.jpg

 

Both the redirect uri on the AAD app registration and on code are same. I have done all the code changes as updated by you. Not sure what is causing this issue. 

aksridhar1
Advocate II
Advocate II

@Anonymous  The reason why you are seeing your user name is due to MSAL authenticating. I think the issue is with exchangeTokenAsync(). Can you debug into this and see what is happening after receiving the token. Did you check your token exchange Url to match with AAD app? 

Anonymous
Not applicable

@aksridhar1 

 

The token exchange Uri that I have added in the PVA Authentication section and the AAD Canvas app both matches.

Please find the below snapshot of exchangeTokenAsync() function code with breakpoint

 

code2.jpg

Below error is what i see on my console as well.

code1.jpg

Anonymous
Not applicable

Hi @aksridhar1 

 

I was successfully able to achieve SSO. I did the changes on the PVA Authentication section by changing the Service Provider from Generic OAuth 2 to Azure Active Directory V2 which was the main reason for the POST error that I was getting in the console. By doing this and the code changes that you have provided me help me a lot to successfully achieve SSO. Many Thanks.

Helpful resources

Announcements

Power Platform Connections - Episode 7 | March 30, 2023

Episode Seven of Power Platform Connections sees David Warner and Hugo Bernier talk to Dian Taylor, alongside the latest news, product reviews, and community blogs.     Use the hashtag #PowerPlatformConnects on social media for a chance to have your work featured on the show.     

Announcing | Super Users - 2023 Season 1

Super Users – 2023 Season 1    We are excited to kick off the Power Users Super User Program for 2023 - Season 1.  The Power Platform Super Users have done an amazing job in keeping the Power Platform communities helpful, accurate and responsive. We would like to send these amazing folks a big THANK YOU for their efforts.      Super User Season 1 | Contributions July 1, 2022 – December 31, 2022  Super User Season 2 | Contributions January 1, 2023 – June 30, 2023    Curious what a Super User is? Super Users are especially active community members who are eager to help others with their community questions. There are 2 Super User seasons in a year, and we monitor the community for new potential Super Users at the end of each season. Super Users are recognized in the community with both a rank name and icon next to their username, and a seasonal badge on their profile.    Power Apps  Power Automate  Power Virtual Agents  Power Pages  Pstork1*  Pstork1*  Pstork1*  OliverRodrigues  BCBuizer  Expiscornovus*  Expiscornovus*  ragavanrajan  AhmedSalih  grantjenkins  renatoromao    Mira_Ghaly*  Mira_Ghaly*      Sundeep_Malik*  Sundeep_Malik*      SudeepGhatakNZ*  SudeepGhatakNZ*      StretchFredrik*  StretchFredrik*      365-Assist*  365-Assist*      cha_cha  ekarim2020      timl  Hardesh15      iAm_ManCat  annajhaveri      SebS  Rhiassuring      LaurensM  abm      TheRobRush  Ankesh_49      WiZey  lbendlin      Nogueira1306  Kaif_Siddique      victorcp  RobElliott      dpoggemann  srduval      SBax  CFernandes      Roverandom  schwibach      Akser  CraigStewart      PowerRanger  MichaelAnnis      subsguts  David_MA      EricRegnier  edgonzales      zmansuri  GeorgiosG      ChrisPiasecki  ryule      AmDev  fchopo      phipps0218  tom_riha      theapurva  takolota     Akash17  momlo     BCLS776  Shuvam-rpa     rampprakash  ScottShearer     Rusk  ChristianAbata     cchannon  Koen5     a33ik  Heartholme     AaronKnox  okeks      Matren   David_MA     Alex_10        Jeff_Thorpe        poweractivate        Ramole        DianaBirkelbach        DavidZoon        AJ_Z        PriyankaGeethik        BrianS        StalinPonnusamy        HamidBee        CNT        Anonymous_Hippo        Anchov        KeithAtherton        alaabitar        Tolu_Victor        KRider        sperry1625        IPC_ahaas      zuurg    rubin_boer   cwebb365   Dorrinda   G1124   Gabibalaban   Manan-Malhotra   jcfDaniel   WarrenBelz   Waegemma   drrickryp   GuidoPreite      If an * is at the end of a user's name this means they are a Multi Super User, in more than one community. Please note this is not the final list, as we are pending a few acceptances.  Once they are received the list will be updated. 

Check out the new Power Platform Communities Front Door Experience!

We are excited to share the ‘Power Platform Communities Front Door’ experience with you!   Front Door brings together content from all the Power Platform communities into a single place for our community members, customers and low-code, no-code enthusiasts to learn, share and engage with peers, advocates, community program managers and our product team members. There are a host of features and new capabilities now available on Power Platform Communities Front Door to make content more discoverable for all power product community users which includes ForumsUser GroupsEventsCommunity highlightsCommunity by numbersLinks to all communities Users can see top discussions from across all the Power Platform communities and easily navigate to the latest or trending posts for further interaction. Additionally, they can filter to individual products as well.         Users can filter and browse the user group events from all power platform products with feature parity to existing community user group experience and added filtering capabilities.     Users can now explore user groups on the Power Platform Front Door landing page with capability to view all products in Power Platform.    Explore Power Platform Communities Front Door today. Visit Power Platform Community Front door to easily navigate to the different product communities, view a roll up of user groups, events and forums.

PVA Conversation Boosters Release

Today, we are excited to unveil new features within Power Platform that incorporate next-generation AI, in including conversation boosters with Power Virtual Agents and AI Builder introducing a create text with GPT model. These features bring both a new way for developers to solve business problems and a new way for end-users to leverage AI in the flow of their work to be more productive. This is a glimpse of what’s to come as we continue to ramp up our investment in AI across Power Platform.   We recognize the significance of both AI and low code for organizations and the benefits these technologies in union can have for all developers: a more intuitive, iterative experience for citizen developers and accelerated development for professional developers.      We announced AI Builder 4 years ago as the first AI capability in Power Platform, followed by Power Apps Ideas 18 months ago, which was the first infusion of generative AI in a commercially- available product.  And we have continued to invest, with the addition of express design in Power Apps, and description to flow in Power Automate late last year.      Today, we’re taking another big step forward in this journey with the launch of next-generation AI features for Power Virtual Agents and AI Builder, enabled by Azure Open AI service.     New! – Conversation booster in Microsoft Power Virtual Agents New! – Create text with GPT model in AI Builder AI Builder create text with GPT model  Read the full Product blog here: https://aka.ms/PP-GPT     **Tips & tricks for using the Power Virtual Agents Boost Conversational Coverage Preview:  Solved: Tips & tricks for using the Power Virtual Agents B... - Power Platform Community (microsoft.com)  

Microsoft Power Platform Conference | Registration Open | Oct. 3-5 2023

We are so excited to see you for the Microsoft Power Platform Conference in Las Vegas October 3-5 2023! But first, let's take a look back at some fun moments and the best community in tech from MPPC 2022 in Orlando, Florida.   Featuring guest speakers such as Charles Lamanna, Heather Cook, Julie Strauss, Nirav Shah, Ryan Cunningham, Sangya Singh, Stephen Siciliano, Hugo Bernier and many more.   Register today: https://www.powerplatformconf.com/   

Announcing Copilot in Power Virtual Agents!

Following our recent release of Conversation Boosters for PVA, today we’re excited to go further and announce Copilot for Power Virtual Agents!     With Copilot, using the power of Azure Open AI, you simply describe what you would like your bot to, using natural language, and Copilot will build an entire PVA topic - ready to use in seconds!     What can the new Copilot in Power Virtual Agents do?    CREATE entire topic from scratch with a simple description.  REFINE content in an existing topic, such as asking for additional questions to be added or updating existing nodes (example: providing message variations).   SUMMARIZE information collected from a user with adaptive cards.  ITERATE over just part of a dialog with specific node selection.    Try Copilot in Power Virtual Agents now: https://aka.ms/tryPVA     Learn more in the full blog post: https://aka.ms/GPT-PP  

Top Solution Authors
Users online (8,232)