howdyai / botkit

Botkit is an open source developer tool for building chat bots, apps and custom integrations for major messaging platforms.
MIT License
11.38k stars 2.29k forks source link

How to recover from a BotFrameworkAdapter message rejection (401 error)? #2200

Closed pgoldweic closed 2 years ago

pgoldweic commented 2 years ago

As I explained in a different post, when I try to connect my botkit bot to the BotFrameworkAdapter, the bot's log shows an unauthorized error. Independently of how to resolve that issue, my question here is how to recover from it, given that later versions of nodejs cause the bot script to exit given the unhandled exception within a promise (taking the bot down completely). Here's the complete stack trace for the error:

   Experienced an error inside the turn handler Error: BotFrameworkAdapter.processActivity(): 401 ERROR
   Error: Unauthorized. Invalid AppId passed on token: 409758d1-171a-471c-8350-0eee0f6af8b6
   at Object.<anonymous> (D:\eclipse-projects\testing-botkit4\node_modules\botframework-connector\lib\auth\emulatorValidation.js:149:23)
   at Generator.next (<anonymous>)
   at fulfilled (D:\eclipse-projects\testing-botkit4\node_modules\botframework-connector\lib\auth\emulatorValidation.js:12:58)
   at processTicksAndRejections (node:internal/process/task_queues:96:5)
   at BotkitBotFrameworkAdapter.<anonymous> (D:\eclipse-projects\testing-botkit4\node_modules\botbuilder\lib\botFrameworkAdapter.js:743:27)
   at Generator.throw (<anonymous>)
   at rejected (D:\eclipse-projects\testing-botkit4\node_modules\botbuilder\lib\botFrameworkAdapter.js:13:65)
   at processTicksAndRejections (node:internal/process/task_queues:96:5)
    node:internal/process/promises:265
          triggerUncaughtException(err, true /* fromPromise */);
          ^
    Error: BotFrameworkAdapter.processActivity(): 401 ERROR
    Error: Unauthorized. Invalid AppId passed on token: 409758d1-171a-471c-8350-0eee0f6af8b6
    at Object.<anonymous> (D:\eclipse-projects\testing-botkit4\node_modules\botframework-connector\lib\auth\emulatorValidation.js:149:23)
    at Generator.next (<anonymous>)
    at fulfilled (D:\eclipse-projects\testing-botkit4\node_modules\botframework-connector\lib\auth\emulatorValidation.js:12:58)
   at processTicksAndRejections (node:internal/process/task_queues:96:5)
   at BotkitBotFrameworkAdapter.<anonymous> (D:\eclipse-projects\testing-botkit4\node_modules\botbuilder\lib\botFrameworkAdapter.js:743:27)
   at Generator.throw (<anonymous>)
   at rejected (D:\eclipse-projects\testing-botkit4\node_modules\botbuilder\lib\botFrameworkAdapter.js:13:65)
   at processTicksAndRejections (node:internal/process/task_queues:96:5)

NOTE: I updated the nodejs version last week, resulting in this problem. In order to handle this exception properly, where should code be inserted for this purpose? Should this be part of the botkit codebase? I am really not too familiar with the internals to be able to tell where one could try to catch this type of exceptions. Any help will be appreciated.

Here are my bot's specs:

Botkit version: 4.10.0 Messaging platform: trying to connect to Azure Bot service (webchat channel is the aim) via botkit's BotFrameworkAdapter (web adapter works fine on original bot) Node version: 16.14.0 OS: Windows (for development)

benbrown commented 2 years ago

It looks like there is not a great way to handle this error if you use the automatically created webhook endpoints. However, you can manage your own endpoint and call the adapter directly as seen in the example below:

https://github.com/howdyai/botkit/blob/93650237bd19a8cc8aac379436c30f8bb0116c14/packages/testbot/multiadapter.js#L53

benbrown commented 2 years ago

@pgoldweic let me know if I can help more...

pgoldweic commented 2 years ago

Thanks @benbrown for your input here. I have two follow-up questions though: 1- Since I don't create the built-in Botkit adapter (which is the one used for Microsoft's webchat), how do I reference it so that I can call its 'processActivity' method? (this is what's used in the example you shared - thanks for pointing to this code), and also, 2- Is there any disadvantage in defining manually the webhook endpoint in this manner vs. using the automated one? (meaning, is there more that needs to be implemented, or does that code example reflect the totality of what's needed?). Thanks in advance.

benbrown commented 2 years ago
  1. You would tell botkit NOT to create the webhook automatically. Basically, you would disable the built in feature, and provide your own version.

To do this, you actually need to set up your own instance of Express, then set up the /api/messages endpoint.

That said, you can basically copy the code from inside Botkit: https://github.com/howdyai/botkit/blob/main/packages/botkit/src/core.ts#L374

Alas, It is a little bit involved.

  1. There shouldn't be any major disadvantage. Just make sure to set up the express instance with the same options that Botkit would internally.
pgoldweic commented 2 years ago

Thanks again @benbrown for your help. I'll check it out.

benbrown commented 2 years ago

@pgoldweic I created a sample that demonstrates how to use your own instance of Express, thus gain access to some of these internal features.

https://github.com/howdyai/botkit/blob/main/packages/testbot/custom_express.js

pgoldweic commented 2 years ago

Perfect. Thanks @benbrown