Hello @Shingo Takada
Thank you for the detailed investigation and validation steps, strongly suggests this is not an authentication failure, but rather a connector-level authorization mismatch during outbound activity validation.
From the behavior you described:
-
401 occurs only when the token audience/scope is intentionally incorrect
-
400 occurs when required activity fields are removed
-
403 occurs only when everything appears valid
This confirms:
- token acquisition is working,
- the JWT is accepted,
- the request body passes schema validation,
- but the Bot Connector service is rejecting the outbound conversation authorization step.
The most likely cause here is a mismatch between:
- the bot identity,
- the conversation/channel binding,
- and the
serviceUrl being used for the outbound request.
A few important things stand out from your example.
For Single-Tenant bots, the Bot Connector Service performs stricter validation to ensure:
- the bot identity in the JWT matches the bot identity known to the conversation,
- the conversation belongs to the same channel/serviceUrl scope,
- and the bot is authorized for that specific conversation instance.
One important detail: You are sending requests to:
https://webchat.botframework.com/v3/conversations/{conversationId}/activities
However, conversation IDs and service URLs are channel-specific.
For example:
- Teams conversations must use the Teams
serviceUrl
- Web Chat conversations must use the Web Chat connector
- Direct Line conversations require Direct Line endpoints/tokens
A Teams conversation cannot reliably be reused against the Web Chat connector endpoint.
This can produce the exact silent 403 behavior you are seeing.
Another likely contributor is the from.id value.
In your snippet you are explicitly setting:
from: { id: appId, name: "Bot" }
However, the connector service validates the bot identity against the channel-specific bot ID not always the raw Azure AD App ID.
For Teams/Web Chat, the bot identity is often something like:
28:<bot-guid>
rather than:
330b21ae-f364-...
If those identities do not match exactly, the connector authorization layer may reject the send operation with a 403.
Recommended changes:
- Do not hardcode the
from field
Either omit the from field entirely and allow the SDK/ConnectorClient to populate it automatically, or use the inbound activity recipient ID:
from: {
id: turnContext.activity.recipient.id
}
instead of the Azure AD App ID.
- Use the exact inbound
serviceUrl
Do not hardcode:
https://webchat.botframework.com
Instead use:
const serviceUrl = turnContext.activity.serviceUrl;
MicrosoftAppCredentials.trustServiceUrl(serviceUrl);
const client = new ConnectorClient(credentials, {
baseUri: serviceUrl
});
The outbound request must use the exact same serviceUrl that arrived on the inbound activity.
- Ensure conversationId + serviceUrl originate from the same activity
The following values must belong together:
-
conversation.id
-
channelId
-
serviceUrl
Mixing them across channels causes connector authorization failure.
- Channel-specific note
For Teams specifically outbound sends/proactive messaging require the bot to be installed in that exact tenant/chat/team scope, and the connector validates tenant/conversation membership before allowing sends.
Even if inbound messages succeed, outbound sends can still fail if the connector does not recognize the bot as authorized for that specific conversation context.
- Direct Line / Web Chat clarification
Web Chat and Direct Line use different authentication expectations than Teams.
If using:
https://directline.botframework.com
you generally need Direct Line tokens/secrets rather than Connector API AAD tokens.
Using ConnectorClient and https://api.botframework.com/.default against the wrong channel endpoint can also result in silent 403 responses.
Please refer this
Azure Bot Service authentication troubleshooting https://docs.microsoft.com/azure/bot-service/bot-service-troubleshoot-authentication-problems?view=azure-bot-service-4.0
Teams bot status codes (403 = InvalidBotApiHost / NotEnoughPermissions) https://learn.microsoft.com/microsoftteams/platform/bots/build-conversational-capability?wt.mc_id=knowledgesearch_inproduct_azure-cxp-community-insider#status-codes-from-bot-conversational-apis
Direct Line REST API reference (HTTP status codes) https://docs.microsoft.com/azure/bot-service/rest-api/bot-framework-rest-direct-line-3-0-api-reference?view=azure-bot-service-4.0#http-status-codes
General HTTP-error guide for Bot Service https://docs.microsoft.com/azure/bot-service/bot-service-troubleshoot-general-problems?view=azure-bot-service-4.0
I Hope this helps. Do let me know if you have any further queries.
If this answers your query, please do click Accept Answer and Yes for was this answer helpful.
Thank you!