1

My goal is to create an HTML page with JavaScript that runs this Microsoft Bot Framework v4 Web Chat Control

https://github.com/Microsoft/BotFramework-WebChat

As described in the comments for this StackOverflow question

Microsoft Bot Framework image size in adaptive card

I tried to follow the sample code here

https://github.com/compulim/BotFramework-MockBot

specifically

BotFramework-WebChat-master\samples\01.a.getting-started-full-bundle

but could not get it working. In the other question linked above, I was told by Microsoft support to authenticate another way:

You need to make a POST request to https://directline.botframework.com/v3/directline/tokens/generate with Authorization: Bearer in the header. Alternatively, you can use const token = directly, instead

However, in the sample code noted above, it says

To talk to your bot, you should use the token exchanged using your Direct Line secret. You should never put the Direct Line secret in the browser or client app.

If the code suggested above is JavaScript included in an HTML file, it is visible from View Source by anyone who loads the page.

Using the DirectLine secret seems to violate the rule to not expose this secret, which I've read could provide access to all conversations, not only the current one.

If the JS code in plain view uses the DirectLine secret to get a token, then uses the token to authenticate, using the token doesn't seem to accomplish anything, as the DL secret is exposed. Why not just use DL secret?

What is the Microsoft-recommended, simplest way to authenticate to the web chat control linked to above?

Thanks!

MindModel
  • 822
  • 1
  • 10
  • 22

1 Answers1

2

Why not just use DL secret?

As you said, this would allow access to all conversations with the bot.

If the JS code in plain view uses the DirectLine secret to get a token, then uses the token to authenticate, using the token doesn't seem to accomplish anything, as the DL secret is exposed.

Correct again. To keep your secret hidden, you'd need to set up your own token server. We don't have an official, ready-to-go sample of how how to set this up, but this sample by the Web Chat author should get you started.

If you want to write your own, the flow would basically be:

  1. Have your WebChat client send a request for a token to your token server
  2. Your token server can store the secret in a variable, so long as you don't make the code public. Have your token server reach out to https://directline.botframework.com/v3/directline/tokens/generate with a POST request and the header, Authorization: Bearer <YourSecret>
  3. Return the token that results from that request back to the WebChat client
    • Your WebChat client will now have a token without ever needing to know the secret because it used your token server middleware

What is the Microsoft-recommended, simplest way to authenticate to the web chat control linked to above?

Unfortunately, there is no method that is both "simple" and "recommended". The simplest is to just use your secret, directly. This is fine if you don't care that user conversations can be exposed. The recommended way, though, is to implement your own token server.


Additional Reading on Exposing the Secret

From this GitHub issue

For purposes of this discussion, we're going to treat secrets and tokens to be the same thing. We can go into detail on those later if you want. I'll refer to them as "secret/token" for now.

To access a conversation, you need the secret/token and a conversation ID. These values are sometimes glued together, and are sometimes in separate variables. Sometimes they're in the URL, and sometimes they're stored in JavaScript in memory. These are similar to a user token, stored in a user's cookie.

In all cases, these values are accessible to a user sitting at their own computer. They can read their own URLs, they can read their own JavaScript variable state, and they can read their own cookies.

If they send any of this information to someone else, that person can impersonate them. If my bank emails me a password reset link, and I share that with someone else, that person can reset my account password and log in to my account.

Our iFrame uses URLs to pass these parameters, as that's an adequate level of security in many cases. (Have you ever visited a website, manually extracted the URL to an iFrame, sent it to someone else, and expected your session to remain private? Probably not.)

If you want additional security, you can skip the iFrame and send your own secret/token inside JS or a cookie. Your JS can extract that and send it to the Web Chat JS object. Once Web Chat has the secret/token, is exclusively uses HTTP Authorization headers to send those values to the Direct Line service.

So, leaving your secret exposed isn't a big deal, per se. However, it does allow a nefarious user to impersonate any other user.

This is default behavior because Directline needs some way to figure out who it is authenticated to talk to. The secret verifies that the client (Web Chat) is okay. But what verifies that the user is? A user id? But then any user could set their own user id and impersonate somebody else. The only way to really secure this is to implement something on your own end that uses the secret to get a Directline token, then passes that back to the Web Chat client.

Also, to get conversation data, somebody would need both the secret and the conversation id. The likelihood of figuring out the conversation id is pretty small.

Generally speaking though, this security is only a concern if you're trying to persist user data. If your users would start a new conversation each time they open the bot, you can just generate a unique user id and not worry if the secret is exposed.

Here's a good blog post regarding creating a Client Controller (token server) in C# and Node as well as some additional security features/concepts..

Here's another blog post on additional security considerations and using Enhanced DirectLine Authentication Features

mdrichardson
  • 7,141
  • 1
  • 7
  • 21
  • @MindModel Did you delete your comments or did they auto-delete when I updated? I edited my answer to address most of it. For the rest (that I can remember), 1) Health Bot uses OAuth, which send OAuth tokens with every message, so the DirectLine token would be redundant. 2) It should be easier. Thankfully, it isn't terribly difficult to spin up a simple token server. The one I linked to in my answer is more complex than it really needs to be. The blog links at the end show easier examples. – mdrichardson May 27 '19 at 21:25
  • Yes, I did. I read your answer before you added the additional material. So I figured it best to delete my comments, read your answer, implement, make sure I get it working, etc. Thank you for your attention here. As an aside, the Health Bot seems to be down. Clicking the Demo button has no effect, on any browser (IE, Chrome, Firefox). – MindModel May 27 '19 at 22:10
  • I will look at the additional token server examples. What concerned me was not the "white board" case. :) The code you described is very simple. But looking at the first example you mentioned, I figured they wouldn't spin up something so complex unless is was necessary. Easy for me to write a few lines of code that does what you described. Not easy to imagine what it's missing and when/why it will break. – MindModel May 27 '19 at 22:12
  • Also not clear what the difference between the web chat control and the iFrame approach is. Seems like they are the same thing, but the iFrame passes in a DL secret and the web chat control expects a token. However that doesn't explain why the iFrame approach causes the code to attach style attributes to the img elements. I assume the web chat approach doesn't do this, which is why I would use it, so I can style the img elements with CSS rules. – MindModel May 27 '19 at 22:15
  • If the iFrame approach would emit HTML/CSS that did NOT add style attributes to the img elements it emits, I wouldn't have to deal with any of this. I could simply add a few CSS rules to my host web page and be done with it. – MindModel May 27 '19 at 22:16
  • 1
    Gotcha. 1) Not sure why the Health Bot demo is down, but I see that, too. 2) Biggest gotcha to watch out for would be token refresh. I think the tokens expire every 30 mins. 3) So, if you get the iFrame from the Azure Portal, it uses an older version of WebChat, BotChat, that's missing a lot of features. It's more difficult to update, so we do it less frequently. 4) Change `token` to `secret` and you can use the secret (I believe it works, even if you set the secret as `token`). – mdrichardson May 27 '19 at 22:24
  • All very good to know. Will try it. I know that the work of keeping the doc up-to-date is endless, but it seems like the thing to change to improve my use case here is the doc, not really the code. – MindModel May 27 '19 at 23:51
  • 1
    Thank you again for your support. I still have a bunch of questions (eg why couldn't I get the sample code to work) but it will take time to try the approaches you've suggested and read the doc you referenced. So I'll close this ticket and create separate SO posts for specific issues as they arise. – MindModel May 29 '19 at 10:00