cancel
Showing results for 
Search instead for 
Did you mean: 
Reply
HemanthN
Helper III
Helper III

How to configure SSO in PVA?

Hi,

 

I am trying to connect SSO in PVA on the Sharepoint website. I see the below error on the chrome console.

p1.png

I see a syntax error from the below line of code. I am following the SSO configuration by the doc provided below: "https://docs.microsoft.com/en-us/power-virtual-agents/configure-sso"

 

The below code is from the doc.

 

 var userID = clientApplication.account?.accountIdentifier != null ? ("Your-customized-prefix-max-20-characters" + clientApplication.account.accountIdentifier).substr(0,64) : (Math.random().toString() + Date.now().toString().substr(0,64)

 

I had posted by query before as well but no luck.. https://powerusers.microsoft.com/t5/General/How-to-configure-Single-Sign-On-in-PVA-with-Sharepoint-a...

 

Can anyone please help me out here?

 

Regards,

Hemanth

34 REPLIES 34
renatoromao
Super User
Super User

Hi @HemanthN ,

 

Try to change the phrase "your prefix...".

 var userID = clientApplication.account?.accountIdentifier != null ? ("mypva" + clientApplication.account.accountIdentifier).substr(0,64) : (Math.random().toString() + Date.now().toString().substr(0,64)

 

Did you change the variables e codes that contain ClientId and BotId?

Like 

  var BOT_ID = "<BOT ID>";

Did I answer your question? Mark my post as a solution!
Thanks!

Renato Romão,

Connect with me here 😉

Power Virtual Agents course (+2.650 students) : English | Português

Hi @renatoromao ,

 

I have added the bot id,client id of the canvas app and the tenant id/Directory ID were it is required as per the code.

 

And also we have created 2 app registrations on the Azure AD one for Authentication and the other for SSO.

 

On adding the below code as you have suggested. I still see the same syntax error.

p2.png

Regards,

Hemanth

BoLi
PVA
PVA

Hi Hemanth, 

 

I think it is because there is a missing close bracket in the code sample in SSO document. Thank you for raising that issue out. You can change the line of code to below to fix the issue.

var userId = clientApplication.account?.accountIdentifier != null ?
                                  ("You-customized-prefix" + clientApplication.account.accountIdentifier).substr(0, 64)
                                  : (Math.random().toString() + Date.now().toString()).substr(0,64);    

 

see the hightlighted close bracket after Date.Now().toString().

 

Best Regards

Bo

Hi @BoLi ,

 

Thank you for your response. I have tried added the closed bracket but i still see the same error. Kindly have a look at the attached snapshot for your reference.

 

p3.png

Regards,

Hemanth

Hi Hemanth, 

 

sorry that there are some issue in the document and our doc writer is updating that. Meanwhile you can use the sample sso code on github to unblock you.

 

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

 

Thanks

Bo

@HemanthN we also updated our documentation example. Let us know if these solved the issue for you.

 

 

https://docs.microsoft.com/en-us/power-virtual-agents/configure-sso

 

Thanks

Hi @CleberM / @BoLi ,

 

I still see the same syntax error even after trying the updated code from the SSO doc. I have even tried the sample code from github. Both are having the same syntax error.

 

p5.png

 

Regards,

Hemanth

Hi @CleberM / @BoLi / @renatoromao  ,

 

I am still not able to configure SSO. I am try to achieve this on a Sharepoint Webpage. I have posted the issue through multiple thread but no luck.

I am still being asked to pass the token id.

Can you please help me out with this? Any help is much appreciated.

https://powerusers.microsoft.com/t5/General/PVA-SSO-Configuration/td-p/650994/jump-to/first-unread-m...

 

e1.pnge2.png

 

Below is the code that i am using. I have added a button on the Sharepoint site so the chat bot come up in clicking on it. The same Home page URL were the button is added is the redirect URL that is added on Azure AD App registration.

 

<!DOCTYPE html>
<html>
<head>
    <title>Contoso Sample Web Chat</title>

    <meta name="viewport" content="width=device-width, initial-scale=1">

    <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>
        body {
            font-family: Arial, Helvetica, sans-serif;
        }

        /* The Modal (background) */
        .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 */
        .modal-content {
            background-color: #fefefe;
            margin: auto;
            padding: 10px;
            border: 1px solid #888;
            width: 500px;
            height: 575px;
        }

        /* The Close Button */
        .close {
            color: black;
            float: right;
            font-size: 28px;
            font-weight: bold;
        }

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

        html, body {
            height: 100%;
        }

        body {
            margin: 0;
        }

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

        #webchat {
            position: center;
            height: 530px;
            width: 100%;
            top: 60px;
            overflow: hidden;
        }
		.heading{
		padding-bottom: 5px;
		}
		.span{
        font-weight: bold;
        }
		
    </style>
</head>
<body>

<!--Button and ChatBot View-->

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

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

        <!-- Modal content -->
        <div class="modal-content" style=" background-color: #FFD933">
            <span class="close">&times;</span>

            <div class="chat">
                <div class="heading">
                    <!-- Change the h1 text to change the bot name -->
				
    <img src="heading image added here" width="42" height="30" alt="logo">

                    <span class="span"><strong>Heading</strong></span>
                </div>
                <div id="webchat" role="main"></div><br>
            </div>
        </div>
    </div>


    <!--Button code begins here-->
    <script>
        // Get the modal
        var modal = document.getElementById("myModal");

        // Get the button that opens the modal
        var btn = document.getElementById("myBtn");

        // Get the <span> element that closes the modal
        var span = document.getElementsByClassName("close")[0];

        // When the user clicks the button, open the modal
        btn.onclick = function () {
            modal.style.display = "block";
        }

        // When the user clicks on <span> (x), close the modal
        span.onclick = function () {
            modal.style.display = "none";
        }

        // When the user clicks anywhere outside of the modal, close it
        window.onclick = function (event) {
            if (event.target == modal) {
                modal.style.display = "none";
            }
        }
    </script>
    <!--Button code ends here-->


    <!--SSO Code is added here-->
<script>

	
    function getOAuthCardResourceUri(activity) 
	{

        //alert("activity var inside getOAuthCardResourceUri: " + JSON.stringify(activity));

        if (activity && activity.attachments && activity.attachments[0] && activity.attachments[0].contentType === 'application/vnd.microsoft.card.oauth' && activity.attachments[0].content.tokenExchangeResource) 
		{
            // asking for token exchange with AAD

            //alert("Inside if condition of activity: " + JSON.stringify(activity.attachments[0].content.tokenExchangeResource.uri));

            return activity.attachments[0].content.tokenExchangeResource.uri;
        }
    }

    function exchangeTokenAsync(resourceUri) 
	{
	
        let user = clientApplication.getAccount();
		
		//alert("user value inside exchangeTokenAsync: " + JSON.stringify(user));
        debugger;
		if (user) 
		{
            let requestObj = 
			{
                scopes: [resourceUri]
            };
			//alert("requestObj inside exchangeTokenAsync: " + JSON.stringify(requestObj));
            return clientApplication.acquireTokenSilent(requestObj)
                    .then(function (tokenResponse) 
					{
                        return tokenResponse.accessToken;
                    })
                    .catch(function (error) 
					{
                        console.log(error);
                    });
            }
            else 
			{
                return Promise.resolve(null);
            }
        }
		
		async function fetchJSON(url, options = {}) 
		{
			//alert("url inside fetchJSON: " + JSON.stringify(url));
			const res = await fetch(url, {
				...options,
				headers: 
				{
					...options.headers,
					accept: 'application/json'
				}
		});
		//alert("res inside fetchJSON: " + JSON.stringify(res));
		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: '<Client Id of canvas>',
                    authority: 'https://login.microsoftonline.com/<Directory ID>'
                },
                cache: 
				{
                    cacheLocation: 'localStorage',
                    storeAuthStateInCookie: false
                }
            };
			
            if (!clientApplication) 
			{
                
                //alert("msalConfig: " + JSON.stringify(msalConfig));
                
				clientApplication = new Msal.UserAgentApplication(msalConfig);
				
				//alert("clientApplication inside if: " + JSON.stringify(clientApplication));
            }
        }());
	
	
        (async function main() {
 // Add your BOT ID below
            var BOT_ID = "ABC";
            var theURL = "https://powerva.microsoft.com/api/botmanagement/v1/directline/directlinetoken?botId=" + BOT_ID;

            const styleOptions = {

                botAvatarImage: "BOT image",
                userAvatarImage: "user image",
                hideUploadButton: true
            };
			
             const { token } = await fetchJSON(theURL);
            const directLine = window.WebChat.createDirectLine({ token });
            
             var userID = clientApplication.account?.accountIdentifier != null ?
                ("mypva" + clientApplication.account.accountIdentifier).substr(0, 64)
                : (Math.random().toString() + Date.now().toString()).substr(0,64);

            
            //alert("userID inside async function is " + userID);
            

            //alert("Token:" + JSON.stringify(token));

            const store = window.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))) {
						
						//alert("Inside if DIRECT_LINE/INCOMING_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 => {
                                        if (id === 'retry') {
                                            // bot was not able to handle the invoke, so display the oauthCard
                                            return next(action);
                                        }
                                        // else: tokenexchange successful and we do not display the oauthCard
                                    },
                                    error => {
                                        // an error occurred to display the oauthCard
                                        return next(action);
                                    }
                                );
                                return;
                            } else
                                return next(action);
                        });
                    } else
                        return next(action);
                } else
                    return next(action);
            });

            window.WebChat.renderWebChat({
                directLine: directLine,
                store,
                userID: userID,
                styleOptions
            },
                document.getElementById('webchat')
            );
        })().catch(err => console.error("An error occurred: " + err));
    </script>
	
    <!--SSO Code ends here-->

</body>
</html>

 

Regards,

Hemanth

Thank you Hemanth, it is required to pass a token to PVA for exchange in order for SSO to work. Are you able to do SSO use the sample file on github?

Suggest process to debug the issue

1. try to talk to your bot in PVA demo website and check if it can login successfully without SSO.

2. If #1 works, config the token exchange url field based on the SSO document.

3. Download the sample SSO test file on github and check if SSO works. If it does not work, you need to debug the code and see which steps failed the calls. Usually how SSO works is like this. When some user loggined to customer canvas, AAD will issue a login token and the client will call AAD to get an On-behalf-of token based on the login token. This On-behalf-of token will then be passed to PVA service and they will exchange this for a user access token. If you failed any steps above, the call will fail.

 

So you need to debug more into the code and tell what steps failed the call and what the error is so that we can help you

Helpful resources

Announcements
V3_PVA CAmpaign Carousel.png

Community Challenge - Giveaways!

Participate in the Power Virtual Agents Community Challenge

PVA_User Group Leader_768x460.jpg

Manage your user group events

Check out the News & Announcements to learn more.

Carousel 2021 Release Wave 2 Plan 768x460.jpg

2021 Release Wave 2 Plan

Power Platform release plan for the 2021 release wave 2 describes all new features releasing from October 2021 through March 2022.

R2 (Green) 768 x 460px.png

Microsoft Dynamics 365 & Power Platform User Professionals

DynamicsCon is a FREE, 4 half-day virtual learning experience for 11,000+ Microsoft Business Application users and professionals.

Users online (1,935)