I am attempting to build a simple echo bot using the Python bot framework SDK. My bot works locally using the emulator without a problem. I used ngrok to create an https tunnel to my app then I registered the bot using azure bot service (bot type: multitenant). I added the app_id and secret from bot service to my app and when I test sending messages from bot service using "Test in Web Chat" feature, I get error "Unauthorized Access. Request is not authorized" on my app log.
I tested on emulator without credentials and it works, also I can get token successfully with the same app_id and password when I test using: "curl -k -X POST https://login.microsoftonline.com/botframework.com/oauth2/v2.0/token -d "grant_type=client_credentials&client_id=my_app_id_here&client_secret=my_app_secret_here&scope=https%3A%2F%2Fapi.botframework.com%2F.default"
But when I try to send a message from bot service's Test in web chat, I get "Unauthorized Access. Request is not authorized" on app.
Stack trace:
[2024-05-23 22:27:15,827] ERROR in app: Exception on /api/messages [POST]
Traceback (most recent call last):
File "/home/metalmlover/dev/microsoft bot framework/BotTutorialSample/Python_tutorial/01-EchoBot/venv/lib/python3.8/site-packages/flask/app.py", line 1473, in wsgi_app
response = self.full_dispatch_request()
File "/home/metalmlover/dev/microsoft bot framework/BotTutorialSample/Python_tutorial/01-EchoBot/venv/lib/python3.8/site-packages/flask/app.py", line 882, in full_dispatch_request
rv = self.handle_user_exception(e)
File "/home/metalmlover/dev/microsoft bot framework/BotTutorialSample/Python_tutorial/01-EchoBot/venv/lib/python3.8/site-packages/flask/app.py", line 880, in full_dispatch_request
rv = self.dispatch_request()
File "/home/metalmlover/dev/microsoft bot framework/BotTutorialSample/Python_tutorial/01-EchoBot/venv/lib/python3.8/site-packages/flask/app.py", line 865, in dispatch_request
return self.ensure_sync(self.view_functions[rule.endpoint])(**view_args) # type: ignore[no-any-return]
File "/home/metalmlover/dev/microsoft bot framework/BotTutorialSample/Python_tutorial/01-EchoBot/app.py", line 30, in messages
loop.run_until_complete(task)
File "/home/metalmlover/.pyenv/versions/3.8.16/lib/python3.8/asyncio/base_events.py", line 616, in run_until_complete
return future.result()
File "/home/metalmlover/dev/microsoft bot framework/BotTutorialSample/Python_tutorial/01-EchoBot/venv/lib/python3.8/site-packages/botbuilder/core/bot_framework_adapter.py", line 442, in process_activity
identity = await self._authenticate_request(activity, auth_header)
File "/home/metalmlover/dev/microsoft bot framework/BotTutorialSample/Python_tutorial/01-EchoBot/venv/lib/python3.8/site-packages/botbuilder/core/bot_framework_adapter.py", line 551, in _authenticate_request
claims = await JwtTokenValidation.authenticate_request(
File "/home/metalmlover/dev/microsoft bot framework/BotTutorialSample/Python_tutorial/01-EchoBot/venv/lib/python3.8/site-packages/botframework/connector/auth/jwt_token_validation.py", line 49, in authenticate_request
raise PermissionError("Unauthorized Access. Request is not authorized")
PermissionError: Unauthorized Access. Request is not authorized
127.0.0.1 - - [23/May/2024 22:27:15] "POST /api/messages HTTP/1.1" 500 -
127.0.0.1 - - [23/May/2024 22:27:25] "OPTIONS /api/messages HTTP/1.1" 200 -
127.0.0.1 - - [23/May/2024 22:34:59] "OPTIONS /api/messages HTTP/1.1" 200 -
127.0.0.1 - - [23/May/2024 22:35:04] "OPTIONS /api/messages HTTP/1.1" 200 -
[2024-05-23 22:35:08,763] ERROR in app: Exception on /api/messages [POST]
Traceback (most recent call last):
File "/home/metalmlover/dev/microsoft bot framework/BotTutorialSample/Python_tutorial/01-EchoBot/venv/lib/python3.8/site-packages/flask/app.py", line 1473, in wsgi_app
response = self.full_dispatch_request()
File "/home/metalmlover/dev/microsoft bot framework/BotTutorialSample/Python_tutorial/01-EchoBot/venv/lib/python3.8/site-packages/flask/app.py", line 882, in full_dispatch_request
rv = self.handle_user_exception(e)
File "/home/metalmlover/dev/microsoft bot framework/BotTutorialSample/Python_tutorial/01-EchoBot/venv/lib/python3.8/site-packages/flask/app.py", line 880, in full_dispatch_request
rv = self.dispatch_request()
File "/home/metalmlover/dev/microsoft bot framework/BotTutorialSample/Python_tutorial/01-EchoBot/venv/lib/python3.8/site-packages/flask/app.py", line 865, in dispatch_request
return self.ensure_sync(self.view_functions[rule.endpoint])(**view_args) # type: ignore[no-any-return]
File "/home/metalmlover/dev/microsoft bot framework/BotTutorialSample/Python_tutorial/01-EchoBot/app.py", line 30, in messages
loop.run_until_complete(task)
File "/home/metalmlover/.pyenv/versions/3.8.16/lib/python3.8/asyncio/base_events.py", line 616, in run_until_complete
return future.result()
File "/home/metalmlover/dev/microsoft bot framework/BotTutorialSample/Python_tutorial/01-EchoBot/venv/lib/python3.8/site-packages/botbuilder/core/bot_framework_adapter.py", line 442, in process_activity
identity = await self._authenticate_request(activity, auth_header)
File "/home/metalmlover/dev/microsoft bot framework/BotTutorialSample/Python_tutorial/01-EchoBot/venv/lib/python3.8/site-packages/botbuilder/core/bot_framework_adapter.py", line 551, in _authenticate_request
claims = await JwtTokenValidation.authenticate_request(
File "/home/metalmlover/dev/microsoft bot framework/BotTutorialSample/Python_tutorial/01-EchoBot/venv/lib/python3.8/site-packages/botframework/connector/auth/jwt_token_validation.py", line 49, in authenticate_request
raise PermissionError("Unauthorized Access. Request is not authorized")
PermissionError: Unauthorized Access. Request is not authorized
My App Code:
from flask import Flask,request,Response
from botbuilder.schema import Activity
from botbuilder.core import BotFrameworkAdapter,BotFrameworkAdapterSettings
import asyncio
from echobot import EchoBot
app = Flask(__name__)
loop = asyncio.get_event_loop()
botadaptersettings = BotFrameworkAdapterSettings("my_app_id_here","my_app_secret_here")
botadapter = BotFrameworkAdapter(botadaptersettings)
ebot = EchoBot()
@app.route("/api/messages",methods=["POST"])
def messages():
if "application/json" in request.headers["content-type"]:
jsonmessage = request.json
else:
return Response(status=415)
activity = Activity().deserialize(jsonmessage)
async def turn_call(turn_context):
await ebot.on_turn(turn_context)
task = loop.create_task(botadapter.process_activity(activity,"",turn_call))
loop.run_until_complete(task)
return "200"
if __name__ == '__main__':
app.run('localhost',3978)
My bot:
from botbuilder.core import TurnContext
class EchoBot:
async def on_turn(self,turn_context:TurnContext):
await turn_context.send_activity(turn_context.activity.text)
Refer MSDOC. to create an echo Bot using Python framework sdk.
app.py
:
import sys
import traceback
from datetime import datetime
from aiohttp import web
from aiohttp.web import Request, Response, json_response
from botbuilder.core import (BotFrameworkAdapter, BotFrameworkAdapterSettings,
TurnContext)
from botbuilder.core.integration import aiohttp_error_middleware
from botbuilder.schema import Activity, ActivityTypes
from bot import MyBot
from config import DefaultConfig
CONFIG = DefaultConfig()
SETTINGS = BotFrameworkAdapterSettings(CONFIG.APP_ID, CONFIG.APP_PASSWORD)
ADAPTER = BotFrameworkAdapter(SETTINGS)
async def on_error(context: TurnContext, error: Exception):
print(f"\n [on_turn_error] unhandled error: {error}", file=sys.stderr)
traceback.print_exc()
await context.send_activity("The bot encountered an error or bug.")
await context.send_activity(
"To continue to run this bot, please fix the bot source code."
)
if context.activity.channel_id == "emulator":
trace_activity = Activity(
label="TurnError",
name="on_turn_error Trace",
timestamp=datetime.utcnow(),
type=ActivityTypes.trace,
value=f"{error}",
value_type="https://www.botframework.com/schemas/error",
)
await context.send_activity(trace_activity)
ADAPTER.on_turn_error = on_error
# Create the Bot
BOT = MyBot()
# Listen for incoming requests on /api/messages
async def messages(req: Request) -> Response:
# Main bot message handler.
if "application/json" in req.headers["Content-Type"]:
body = await req.json()
else:
return Response(status=415)
activity = Activity().deserialize(body)
auth_header = req.headers["Authorization"] if "Authorization" in req.headers else ""
response = await ADAPTER.process_activity(activity, auth_header, BOT.on_turn)
if response:
return json_response(data=response.body, status=response.status)
return Response(status=201)
def init_func(argv):
APP = web.Application(middlewares=[aiohttp_error_middleware])
APP.router.add_post("/api/messages", messages)
return APP
if __name__ == "__main__":
APP = init_func(None)
try:
web.run_app(APP, host="0.0.0.0", port=CONFIG.PORT)
except Exception as error:
raise error
config.py:
class DefaultConfig:
""" Bot Configuration """
PORT = 3978
APP_ID = os.environ.get("MicrosoftAppId", "<AppID>")
APP_PASSWORD = os.environ.get("MicrosoftAppPassword", "<Password>")
ngrok http 3978 --host-header rewrite
http://127.0.0.1:4040
https://b437-2402-8100-2844-2f53-1181-ffb7-df6c-560d.ngrok-free.app
-> http://localhost:3978
Navigate to Configuration in the Azure Bot=>Settings
, paste the generated ngrok forwarding URL
in the Messaging endpoint field by adding "/api/messages" at the end of the URL.
Test the Bot in Web Chat:
Console Output: