Passing Authentication Context from Dynamics Portals to Chatbot

We have seen many websites with Live Chat embedded on the home page or contact us page, which is what we use to connect to a human agent.

In most of the websites, there is a splash screen on the Live Chat interface that will first gather your Full name, Phone, email and so on and then connect you to an agent.
This is a sort of pattern we see with the Chatbot embeds as well.

Wouldn’t it be nice if the Chatbot is intelligent enough to automatically know who the user is, if the user is already logged to the website? – and say Hello to you by calling your name?

This may appear very obvious and a simple functionality – but there is quite a bit of a moving parts involved and we’ll review everything in this post.

Please be aware that this post is written in the context of Dynamics 365 Portals. The overall concept is the same for any SPA (Single Page Application) websites, provided you use OAuth 2.0 implicit grant flow.

Moving parts involved

For our bot app to be context aware of the user’s fullname, phone and email address, the bot has to have a secure and reliable way to know about the logged in user on the portal. In other words, the bot must know the Authentication Context that the portal itself uses to be aware of the logged in user.

The challenge is that our bot application is a self contained app which is embedded onto the portal’s home page. So, the bot won’t be in a position to understand the authentication context in the portal.

So, we need two mechanisms here:

A mechanism through which we get the Authentication Context from the portal

The Dynamics 365 Portals exposes an endpoint through which we can get a Token, which can be decrypted to retrieve the entire Authentication Context of the logged in user. This is fully documented here.
Dynamics 365 Portal supports Implicit Grant Type, as this way we do not require to use the Client Secret (highly sensitive data) to call the end point because we may have to call the end point using JavaScript on the portal.

A mechanism through we can send the Authentication Context to the bot from the portal.

The Bot api opens up a narrow channel through which some pieces of information can be transmitted from the hosting page (portal’s home page) to the bot – Backchannel technique.
Backchannel is a mechanism through which we exchange custom messages with the bot application that is invisible to the user. Bot receives this activity as Events and processes them.

In the rest of the post, we are going to look at these 2 mechanisms in detail.

So, here are the spoiler alerts to pull this off:

  1. Register your bot application in Azure AD and obtain the client id (application id).
  2. Use JavaScript on the portal to get the Token from the Portal endpoint.
  3. First tier (basic) validation of the obtained Token.
  4. Use bot’s Backchannel to pass the Token to the bot app.
  5. Second tier (comprehensive) validation of the Token.
  6. Decrypt the Token to get the Authentication Context.
  7. Don’t forget to say “hello” to the logged in user 🙂

Register Bot application in Azure AD

There are many blogs that show how to register an application in AD. Here is one. Follow Step 1 through Step 6 to register the bot app in the Azure AD.

Create 2 Site Settings as shown below in the Dynamics 365 as documented here. This is required for the Implicit Grant Flow to work in order to get the Token.

  • ImplicitGrantFlow/RegisteredClientId – Value of this Site Setting is the Client ID copied from the above step during the app registration in Azure AD.
  • ImplicitGrantFlow/{ClientId}/RedirectUri – Ensure to replace {ClientId} with your Client ID and the value of Site setting will be your home page of Dynamics 365 Portal.

JavaScript Library to interact with Portal OAuth Endpoint

Our JavaScript should call the Portals’ endpoint with several parameters as documented here. This endpoint must be called after the user is logged in.

Client ID – That we obtained while Registering the bot application in Azure AD.
Redirect ID – Dynamics 365 Portal home page url as set in the Site Setting above.

If the request to the endpoint succeeds, you will be receiving the response with the token, state and expires_in as documented here.

We need a way to cache the token until it expires (based on expires_in value) so that we are not sending request each and every time the token is needed.
By the way, the token is set to expire in 15 mins (you will see expires_in value 15 * 60 = 900). You can set the value max to 1 hour by adding a Site Setting ImplicitGrantFlow/TokenExpirationTime to 3600.

We need a way to generate an arbitrary State value to be sent in the request and a way to check if the State value obtained in the response fragment matches the value sent.

I am using a JavaScript Library JSO that already implements the OAuth 2.0 Implicit Grant Flow and does the validations described above. However, this GitHub code has a few assumptions/shortcomings:

  • The state code generated by this library is a GUID with more than 20 characters, but the Portal’s OAuth end point does not accept a state value greater than 20.
  • The token name is assumed to be “Access_Token”, whereas the Dynamics 365 Portals names it just “Token”.

I have corrected these shortcomings and generated a new JSO.js file that can be used for our purposes. Download the new JSO.js file.

Add JavaScript to Dynamics 365

Login to the Portal with administrator web role credentials and upload the JSO.js as a webfile.

If you run into issues while uploading the JavaScript as a Webfile, navigate to Settings > Administration > System Settings > General Tab and look at the Set blocked file extensions for attachments section. You should find that js is listed, remove it from the list. You should then be able to upload your js file.

Launch Dynamics 365 and Navigate to Portals -> Webpages and open the Home Webpage and navigate to the associated Web Template (Typically “Home”).
Add the below JavaScript in order to leverage the JSO.js to fetch the token and validation.

  • Replace {Client_Id} with the your Client Id (the one that you got during AD application registration)
  • Replace {Redirect_URI} with your redirect URI (eg., your portal home page url)
  • Replace {Authorization_URL} with <portal_url>/_services/auth/authorize.

Launch the portal and sign in, you will be redirected to the home page. In the Browser’s Developer console, navigate to the “Application” tab and you should see the token, expires_in, received and state. The JSO.js library obtained the token from the Portals end point and persisted in the Local Storage. This library also deals with caching the token and managing the token expiry and fetching the new token when the token expires.

We have successfully retrieved the Token (typically starts with “ey…”) from Dynamics 365 url from the endpoint and performed some basic validation (First-Tier validation).

Launch http://jwt.io and paste the retrieved token in the Encoded section and you will see the decoded user details in the right side panels that contain the full Authentication Context with the client id, Issuer, expiry Full Name, Email address etc., – also known as Claims.

But, we aren’t going to decrypt the Token just yet using JavaScript on the portal’s home page. Rather, we are going to send the entire Token to the bot app, which will be immensely useful for the bot to be aware of the full authentication context of the user.

The Bot application

Feel free to download the bot application code from here. This is simple bot app that echoes whatever you type. I also have additional code to receive the token sent through the Backchannel, perform the second tier validation and finally decrypt the token.

Deploy the bot app to Azure Web App Bot. Test it by typing “Hi” using the “Test in web chat” functionality. The Bot should respond “You said: Hi”.

Here is the source code to pass the Token to the bot application using Backchannel technique. This is essentially a continuation to the previous code that I provided to paste in “Home” Webtemplate above. Paste the below code before the “</script>” tag on the “Home” Webtemplate.

This code renders the Webchat using Direct Line 3.0 framework directly using the Secret Key. Obtain your Directline Channel secret key from Azure Web app and update the code appropriately as shown below. Care should be taken to ensure that the direct line’s secret key is not publicly exposed.

This code also leverages the backchannel technique in order to pass the token to the bot application. Pay attention to the Payload in the below image. The payload contains a name through which we will be accessing the token in the bot app.

Validation and Token Decryption

Once the bot application receives the Token, it needs to perform a few additional validations (second tier validation) before trusting the token. The validation involves:

  • Validating the token signature to ensure that the token is not tampered with. Dynamics Portal exposes an endpoint <portal_url>/_services/auth/publickey through which we can obtain the Public Key. This key is used to validate the token’s signature.
  • Validating the Issuer to ensure that the token is coming from wherever we think it is coming from.
  • Validating the Expiry of the Token.
  • Validating the App ID to ensure that the token is intended to be used by our Bot app.

Bot application’s MyBot.cs file should have all the necessary code to perform the above validations.

Launch the portal and sign in. You should be redirected to the home page. When you click open the embedded bot, the bot should say “Hello <your name>, How can I help you?

A Few Caveats

There are few functionalities that are missing in the process that I described so far. These are something I’d like to add on later.

1 .When the user logs out, the token should be wiped out on the browser and the bot should receive an indication to delete the token that it possesses.

2. Currently, the bot receives token on every page refresh. The bot should only receive the token if it is new to avoid unnecessary overhead.

Final thoughts

The bot being aware of the Authentication Context of the logged-in user opens up a lot of possibilities. Now that we have a way to uniquely identify who the user is, the bot will be able to perform all the operations in the context of the logged in user, which will be really helpful in the context of the virtual agent. We can review how this process looks in the future post.

Hope you found this post useful!

2 thoughts on “Passing Authentication Context from Dynamics Portals to Chatbot

  1. Hello,
    I’m trying to find some guidelines, tutorial or step by step sample for authenticating a Bot Framework V4 user with Azure Activie Directory B2C (allowing sign in through various social network providers) through DotNetCore. WOuld you have any advice for that ?
    Thanks,

    Like

    1. Hi,
      Here is the rough thought process:
      1. Download the source code of WebApp Dotcore Azure B2C from https://github.com/Azure-Samples/active-directory-b2c-dotnetcore-webapp and set it up with your azure b2c configuration.
      2. Create one more Azure B2C application for the Bot to configure Azure B2C.
      3. Download the “Authentication Bot” sample from https://github.com/microsoft/BotBuilder-Samples/tree/master/samples/csharp_dotnetcore/18.bot-authentication.
      4. Create a Web App Bot in Azure and in the “Settings” blade of the Web App Bot, create a new oAuth Connection Setting and name it as “Azure B2C” and choose “Generic oAuth 2” provider and fill out the details and click Save.
      5. Ensure that the Authentication Bot Sample code points to the Connection name “Azure B2C” and deploy it to the Web App Bot.
      6. Enable DirectLine channel and enable “Enhanced Authentication options” and add your web application’s url . for eg., https://localhost:44317.
      7. Finally, in our HomeController.cs, add

      public async Task Index()
      {
      var secret = “wt0qoD4-b6ynw0BvlY”; //your directline secret goes here
      HttpClient client = new HttpClient();
      HttpRequestMessage request = new HttpRequestMessage(
      HttpMethod.Post,
      $”https://directline.botframework.com/v3/directline/tokens/generate”);
      request.Headers.Authorization = new AuthenticationHeaderValue(“Bearer”, secret);
      var userId = $”dl_{Guid.NewGuid()}”;
      request.Content = new StringContent(
      JsonConvert.SerializeObject(
      new { User = new { Id = userId } }),
      Encoding.UTF8,
      “application/json”);
      var response = await client.SendAsync(request);
      string token = String.Empty;
      if (response.IsSuccessStatusCode)
      {
      var body = await response.Content.ReadAsStringAsync();
      token = JsonConvert.DeserializeObject(body).token;
      }
      var config = new ChatConfig()
      {
      Token = token,
      UserId = userId
      };
      return View(config);
      }

      8. And in your index.cshtml, add this

      https://cdn.botframework.com/botframework-webchat/latest/webchat.js

      var user = @Html.Raw(Json.Serialize(Model.UserId));
      var token = @Html.Raw(Json.Serialize(Model.Token));
      window.WebChat.renderWebChat({
      directLine: window.WebChat.createDirectLine({ token: token }),
      userID: user
      }, document.getElementById(‘webchat’));

      Again, I was doing my own Proof of concept and came up with these steps, these are not fully tested. I might put out a blog soon about this as well.

      All the best,

      Dhina

      Like

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s