I am building a Bot Framework bot which needs to be triggered proactively from an Azure Function. I have deployed a prototype to Azure based on this example which currently allows me to POST
to an /api/notify
REST endpoint in order to send messages proactively.
However, I am not sure how to go about adding authentication to the /api/notify
endpoint. Messages to the /api/messages
endpoint are authenticated using the Bot Service API in the application code, but in that example there is no authentication on traffic to the /api/notify
endpoint (I can POST
to it using curl
from my CLI without any tokens or passphrases).
I tried enabling App Service Authentication
on the underlying App Service but then my bot no longer worked in the web chat.
How do I add authentication to this endpoint so only my Azure Function can POST
to it?
I actually just set this up for an internal project a couple of weeks ago. You'll probably need to adapt this strategy to whatever language your bot and function are in, but here's what I did:
Azure Function
module.exports = class BotService {
constructor(context) {
this.context = context;
// Get appId and password from environment variables to build credentials
this.credentials = new MicrosoftAppCredentials(process.env.MicrosoftAppId, process.env.MicrosoftAppPassword);
this.client = axios.create({
baseURL: process.env.BotBaseUrl
});
}
async sendData(body) {
// Get the auth token using the credentials
const token = await this.credentials.getToken();
const response = await this.client.post('/api/data', body, {
// Add the token to the auth header
headers: { Authorization: `Bearer ${ token }` }
});
if (response.status !== 200) {
this.context.error(JSON.stringify(response, null, 2));
} else {
this.context.log(`Successfully sent data to the bot. Response Code: ${ response.status }`);
}
}
}
Bot Note: The bot is in C# and this is in the controller for /api/data
[HttpPost]
public async Task<HttpStatusCode> PostAsync()
{
try
{
// Build the bot credentials
var credentials = new SimpleCredentialProvider(Configuration["MicrosoftAppId"], Configuration["MicrosoftAppPassword"]);
// Grab the auth header from the request
Request.Headers.TryGetValue("Authorization", out StringValues authHeader);
// Use Microsoft.Bot.Connector.Authentication.JwtTokenValidation to validate the auth header
var result = await JwtTokenValidation.ValidateAuthHeader(authHeader, credentials, new SimpleChannelProvider(), Channels.Directline);
if (result.IsAuthenticated)
{
// Do stuff
// Do stuff
return HttpStatusCode.OK;
}
return HttpStatusCode.Forbidden;
}
catch (Exception e)
{
Logger.LogError($"Something went wrong in /api/data controller: {e.Message}");
}
return HttpStatusCode.BadRequest;
}
It looks like your bot is in Python. You can see similar auth validation in one of our Python tests