Search code examples
c#botframework

Value cannot be null. (Parameter 'clientSecret') when sending an activity from a bot


We are trying to send an activity directly to our bot using the /api/messages endpoint for our bot. We are doing this so that we can have 2 Twilio numbers associated with our bot.

First, we get an access token for the bot with the following code:

var authClient = new HttpClient();
var authRequest = new HttpRequestMessage
{
    Method = HttpMethod.Post,
    RequestUri = new Uri($"https://login.microsoftonline.com/botframework.com/oauth2/v2.0/token"),
    Content = new StringContent($"grant_type=client_credentials&client_id={BOT_MIRCOSOFT_APP_ID}&client_secret={BOT_MICROSOFT_APP_PASSWORD}&scope=https%3A%2F%2Fapi.botframework.com%2F.default", Encoding.UTF8, "application/x-www-form-urlencoded"),
};
var authResponse = await authClient.SendAsync(authRequest).ConfigureAwait(false);

We then put this access token in the header of our api call to the bot and send the bot an activity through the /api/messages endpoint. The activity reaches the bot and everything works until we try to send an activity out from the bot. Our AdapterWithErrorHandler class catches an error with the message: Value cannot be null. (Parameter 'clientSecret'). We have searched thoroughly and could not find where this clientSecret variable is.

How can we resolve this error so that we can send an activity out from our bot?

Edit: Here is a sample project that throws this error using an unchanged standard echo bot and a console app. To get it to work you need to put in a valid app id and app password in the console app and the settings of the echo bot. https://github.com/andrew-j-frank/MicrosoftBotErrorSample

Edit: Here is the stack trace for the error:

   at Microsoft.IdentityModel.Clients.ActiveDirectory.ClientCredential..ctor(String clientId, String clientSecret)
   at Microsoft.Bot.Connector.Authentication.MicrosoftAppCredentials.<BuildAuthenticator>b__14_0()
   at System.Lazy`1.ViaFactory(LazyThreadSafetyMode mode)
   at System.Lazy`1.ExecutionAndPublication(LazyHelper executionAndPublication, Boolean useDefaultConstructor)
   at System.Lazy`1.CreateValue()
   at System.Lazy`1.get_Value()
   at Microsoft.Bot.Connector.Authentication.AppCredentials.<BuildIAuthenticator>b__34_0()
   at System.Lazy`1.ViaFactory(LazyThreadSafetyMode mode)
   at System.Lazy`1.ExecutionAndPublication(LazyHelper executionAndPublication, Boolean useDefaultConstructor)
   at System.Lazy`1.CreateValue()
   at System.Lazy`1.get_Value()
   at Microsoft.Bot.Connector.Authentication.AppCredentials.<GetTokenAsync>d__32.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.ConfiguredTaskAwaitable`1.ConfiguredTaskAwaiter.GetResult()
   at Microsoft.Bot.Connector.Authentication.AppCredentials.<ProcessHttpRequestAsync>d__31.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.Bot.Connector.Conversations.<ReplyToActivityWithHttpMessagesAsync>d__10.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.ConfiguredTaskAwaitable`1.ConfiguredTaskAwaiter.GetResult()
   at Microsoft.Bot.Connector.ConversationsExtensions.<ReplyToActivityAsync>d__17.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at Microsoft.Bot.Builder.BotFrameworkAdapter.<SendActivitiesAsync>d__34.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.Bot.Builder.TurnContext.<>c__DisplayClass25_0.<<SendActivitiesAsync>g__SendActivitiesThroughAdapter|1>d.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.ConfiguredTaskAwaitable`1.ConfiguredTaskAwaiter.GetResult()
   at Microsoft.Bot.Builder.TurnContext.<SendActivityAsync>d__24.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
   at SampleBot.Bots.EchoBot.<OnMessageActivityAsync>d__0.MoveNext() in C:\Users\myuser\source\repos\SampleBot\SampleBot\Bots\EchoBot.cs:line 19
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.ConfiguredTaskAwaitable.ConfiguredTaskAwaiter.GetResult()
   at Microsoft.Bot.Builder.ActivityHandler.<OnTurnAsync>d__0.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.ConfiguredTaskAwaitable.ConfiguredTaskAwaiter.GetResult()
   at Microsoft.Bot.Builder.BotFrameworkAdapter.TenantIdWorkaroundForTeamsMiddleware.<OnTurnAsync>d__0.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.ConfiguredTaskAwaitable.ConfiguredTaskAwaiter.GetResult()
   at Microsoft.Bot.Builder.MiddlewareSet.<ReceiveActivityWithStatusAsync>d__3.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.ConfiguredTaskAwaitable.ConfiguredTaskAwaiter.GetResult()
   at Microsoft.Bot.Builder.BotAdapter.<RunPipelineAsync>d__18.MoveNext()

Solution

  • All the code that generates the bearer tokens for user-to-bot messages in the Azure Bot Service is proprietary, so there's not really a publicly-facing explanation for how to generate such a token. The token that you're currently generating is for bot-to-user messages, which I guess is what your question is about anyway. So all your bot has to do to send messages is generate a token just like your channel is doing.

    You actually don't need to generate a token manually since the Bot Framework SDK will do that for you. You can create a connector client like I explained in the answer to your other question, and you just pass in your app ID and password as credentials: Changing the service url for a direct line activity that is sent to our bot

    Of course, all this authentication is optional anyway if you're building your own API. If you don't care about authenticating requests sent to your bot then you don't need to do that, and if you don't care about authenticating requests sent to your channel then you don't need to do that either. Alternatively, you can come up with your own means of authentication rather than using the builtin AAD app registration credentials.