-
Notifications
You must be signed in to change notification settings - Fork 306
Description
I am developing a simple Python Echo Bot on a personal MacBook using the Bot Framework SDK and testing it locally with the Bot Framework Emulator. The bot runs perfectly when configured for an anonymous connection (no App ID/Password).
However, when I provide a valid MicrosoftAppId and MicrosoftAppPassword to both the bot's code and the Emulator, every single message attempt fails with a POST 400 error in the Emulator log. I have performed exhaustive troubleshooting that proves the credentials, code, and network connectivity to Azure are all correct. The failure appears to be happening specifically within the authentication token validation handshake between the Emulator and the Python SDK on macOS.
Environment
Operating System: macOS (Sonoma)
Machine: Personal MacBook Pro (no corporate VPN, firewall, or proxy)
Client: Bot Framework Emulator v4.x.x
Bot Runtime: Python 3.13
Bot Libraries: botbuilder-core, botbuilder-integration-aiohttp (tested with latest and 4.15.0)
What I Have Proven
The bot works 100% correctly when authentication is disabled on both the bot and the Emulator. This confirms the core application logic and local networking are fine.
Network connectivity to Microsoft's authentication servers is working. curl https://login.microsoftonline.com/botframework.com/v2.0/.well-known/openid-configuration returns a valid JSON response.
My system clock is correctly synchronized with time.apple.com.
Exhaustive Troubleshooting Steps Performed
I have systematically eliminated every standard cause for this error:
-
Credential Integrity:
Generated multiple new client secrets (passwords) in the Azure Portal to ensure I was using the "Value" and not the "Secret ID".
Hard-coded the App ID and Password directly into the bot's configuration to eliminate any possibility of environment variables interfering.
Verified the exact credentials being used by the Python adapter at runtime with print statements. The values printed in the terminal are an exact match to the values entered into the Emulator.
-
Network and Environment:
Changed the bot's host from localhost to the explicit IPv4 address 127.0.0.1 to prevent any IPv4/IPv6 name resolution issues.
Verified the endpoint is http and not https for local testing.
Confirmed I am on a personal network with no VPN or external firewalls active.
Used lsof -i :3978 and kill -9 to ensure no other process was using the port.
-
Software State and Versions:
Performed a hard reset of the Bot Framework Emulator by manually deleting its configuration files from ~/Library/Application Support/BotFramework-Emulator/.
Completely deleted and rebuilt the Python virtual environment (venv) to ensure all dependencies were cleanly reinstalled.
Tested with the latest botbuilder-python SDK. When that failed, I uninstalled it and tested with a known stable version (4.15.0). The POST 400 error persists across all versions.
Minimal Reproducible Code
import sys
from aiohttp import web
from botbuilder.core import BotFrameworkAdapter, BotFrameworkAdapterSettings, TurnContext, ActivityHandler
from botbuilder.schema import Activity
from config import DefaultConfig
CONFIG = DefaultConfig()
Confirmed via print statements that these exact values are used
SETTINGS = BotFrameworkAdapterSettings(CONFIG.APP_ID, CONFIG.APP_PASSWORD)
ADAPTER = BotFrameworkAdapter(SETTINGS)
class EchoBot(ActivityHandler):
async def on_message_activity(self, turn_context: TurnContext):
await turn_context.send_activity(f"You said: '{turn_context.activity.text}'")
BOT = EchoBot()
async def messages(req: web.Request) -> web.Response:
try:
activity = Activity().deserialize(await req.json())
auth_header = req.headers.get("Authorization", "")
response = await ADAPTER.process_activity(activity, auth_header, BOT.on_turn)
if response:
return web.json_response(response.body, status=response.status)
return web.Response(status=201)
except Exception as e:
print(f"Error processing activity: {e}", file=sys.stderr)
return web.Response(status=500)
APP = web.Application()
APP.router.add_post("/api/messages", messages)
if name == "main":
try:
web.run_app(APP, host="127.0.0.1", port=3978)
except Exception as error:
raise error
Core Question
Given that the connection works perfectly without authentication, and all credential and environmental issues have been exhaustively ruled out, what could cause the BotFrameworkAdapter to consistently fail its validation of the security token sent by the Emulator?
Is this a known, deep-level bug or incompatibility related to cryptographic libraries (PyJWT, etc.) specifically on macOS? Are there any lower-level debugging tools or logs within the Python SDK or Emulator that can expose the exact reason for the token validation failure?