3

I have a chatbot that works on localhost, and it's working great. I then added a new Bot Channels Registration on Azure for testing, and that works fine too. I did it by taking its Microsoft App ID and password and putting it into my appsettings.json file.

However, I need to add another Bot Channels Registration. When I test it on that registration, my bot returns a 401 unauthorized error. It's because that has a new App ID and password. But I already put the App ID and password from my first registration channel. I need both of them to work.

How can I allow my chatbot to accept multiple App IDs and passwords? Or how do I get rid of that level of security completely (ie. Allow ALL App IDs and passwords)?

AskYous
  • 4,332
  • 9
  • 46
  • 82
  • 1
    Are you using C#, JavaScript or Python? Have you tried creating multiple adapters based on the different app ids? You could dynamically load the right one by using a dynamic endpoint for example. `/api/messages/{app_id}` – Mick Feb 24 '20 at 21:28
  • I'm using dot net. Can you tell me how to create multiple adapters? I can assign each adapter its own app id and app secret? – AskYous Feb 24 '20 at 21:39

2 Answers2

2

The answer, as @Mick suggested, is to create a bot adapter for each channel. You can do something like this if you want it really dynamic:

BotController.cs

[HttpPost, HttpGet]
public async Task PostAsync()
{
    var credentialProvider = new SimpleCredentialProvider(YourAppId, YourAppPassword); // for each adapter
    Adapter = new BotFrameworkHttpAdapter(credentialProvider); // for each adapter
    await Adapter.ProcessAsync(Request, Response, Bot);
}
AskYous
  • 4,332
  • 9
  • 46
  • 82
0

With a custom ICredentialProvider the appid and password can be retrieved from anywhere:

public class MultiCredentialProvider : ICredentialProvider
{
    public Dictionary<string, string> Credentials = new Dictionary<string, string>
    {
        { "YOUR_MSAPP_ID_1", "YOUR_MSAPP_PASSWORD_1" },
        { "YOUR_MSAPP_ID_2", "YOUR_MSAPP_PASSWORD_2" }
    };

    public Task<bool> IsValidAppIdAsync(string appId)
    {
        return Task.FromResult(this.Credentials.ContainsKey(appId));
    }

    public Task<string> GetAppPasswordAsync(string appId)
    {
        return Task.FromResult(this.Credentials.ContainsKey(appId) ? this.Credentials[appId] : null);
    }

    public Task<bool> IsAuthenticationDisabledAsync()
    {
        return Task.FromResult(!this.Credentials.Any());
    }
}

Then, in Startup.cs:

services.AddSingleton<ICredentialProvider, MultiCredentialProvider>();
Eric Dahlvang
  • 8,252
  • 4
  • 29
  • 50
  • How do you mean it can be retrieved from everywhere? If you want to load it from a database and would inject a scoped DatabaseRepository, you'll get an error as ICredentialProvider is a singleton class. Any idea? – emp Sep 01 '20 at 19:46
  • 1
    Dependency injection libraries generally allow the creation of transiently scoped dependencies within a singleton. – Eric Dahlvang Sep 02 '20 at 02:39