Search code examples
javabotframework

Java Bot SDK throws 401 error for proactive message


I'm trying to implement a bot to send proactive messages. I made a proof of concept in NodeJS that works:

const { BotFrameworkAdapter } = require('botbuilder');

const adapter = new BotFrameworkAdapter({
    appId: process.env.MicrosoftAppId,
    appPassword: process.env.MicrosoftAppPassword
});

adapter.onTurnError = async (error) => {
    console.error(error);
};

const cr = require('./test_cr.json');

adapter.continueConversation(cr, async (turnContext) => {
  await turnContext.sendActivity('Node SDK proactive message')
});

Yet when I try to recreate this example using the Java SDK, I get com.microsoft.bot.connector.rest.ErrorResponseException: Status code 401, {"message":"Authorization has been denied for this request."}.

String appId = System.getenv("MicrosoftAppId");
String appPassword = System.getenv("MicrosoftAppPassword");

BotFrameworkAdapter bot = new BotFrameworkAdapter(new SimpleCredentialProvider(appId, appPassword));
ConversationReference cr = mapper.readValue(new File("test_cr.json"), ConversationReference.class);
CompletableFuture<Void> cf = bot.continueConversation(appId, cr, turnContext -> turnContext.sendActivity("Java SDK proactive message").thenApply(resourceResponse -> null));
cf.get();

The conversation reference and app credentials should be the same for both examples. Am I not setting up the Java bot correctly? For reference, I'm using a pretty barebones conversation reference:

{
  "channelId":"msteams",
  "serviceUrl":"https://smba.trafficmanager.net/amer/",
  "conversation":{
    "isGroup":true,
    "conversationType":"channel",
    "tenantId":"xxxxxx",
    "id":"xxxxxx"
  }
}

Solution

  • It sounds like it could be an issue with BotTrustServiceUrl. I can't explain it but in one of my bots, I had to add this additional code to get proactive messages to work (specifically after a restart). Not sure if this is your same issue but it helped me.

    const { MicrosoftAppCredentials } = require('botframework-connector');
    
    // Then in your proactive message section...
    
            const conversationReference = req.body.conversationReference;
            await adapter.continueConversation(conversationReference, async turnContext => {
                // If you encounter permission-related errors when sending this message, see
                // https://aka.ms/BotTrustServiceUrl
    
                MicrosoftAppCredentials.trustServiceUrl(conversationReference.serviceUrl);
                await turnContext.sendActivity(req.body.message);
            });
    

    Now I've also got two other bots where I didn't need to do this. The one that isn't working wihtout this code is using an older SDK so that could be it, both otherwise the proactive message functions are identical so I'm not sure.

    EDIT: I misread the question and didn't notice that you were having trouble with Java SDK, not JavaScript SDK. But perhaps you could use the same method to see if this resolves your issue in Java as well.