Skip to content

[BUG] TeamsInfo.getMember returns 401 on incoming webhook #934

@BramRoets

Description

@BramRoets

Version

  • @microsoft/agents-hosting@1.2.3
  • @microsoft/agents-hosting-extensions-teams@1.2.3

Describe the bug

TeamsInfo.getMember returns 401 "Authorization has been denied for this request" when called from the incoming webhook's TurnContext. Proactive messaging via continueConversation works fine.

The issue is in createConnectorClientWithIdentity in cloudAdapter.ts:

const scope = identity.azp ?? identity.appid ?? 'https://api.botframework.com';
const token = await tokenProvider.getAccessToken(scope);

When processing an incoming webhook, identity is the decoded JWT from the request. This JWT contains azp/appid claims (set to the caller's app ID), so the scope resolves to that app ID instead of https://api.botframework.com. The resulting token is rejected by the Bot Connector API.

continueConversation works because CloudAdapter.createIdentity(appId) only sets aud (no azp/appid), so the scope correctly falls through to https://api.botframework.com.

Stack trace:

AxiosError: Request failed with status code 401
    at settle (node_modules/axios/lib/core/settle.js:19:12)
    at IncomingMessage.handleStreamEnd (node_modules/axios/lib/adapters/http.js:798:11)

To Reproduce

Single-tenant Teams app with a multi-tenant app registration.

// In the webhook handler — fails with 401
export async function webhookLogic(context: TurnContext) {
  const member = await TeamsInfo.getMember(context, context.activity.from!.id!);
}

// In continueConversation — works
await adapter.continueConversation(appId, reference, async (turnContext) => {
  turnContext.activity.channelData = {
    tenant: { id: reference.conversation.tenantId },
  };
  const member = await TeamsInfo.getMember(turnContext, userId);
});

Channel: Microsoft Teams (personal chat)

Expected behavior

TeamsInfo.getMember should work with the TurnContext from an incoming webhook. The token scope for outgoing Bot Connector API calls should be https://api.botframework.com, not derived from the incoming JWT's azp/appid claims.

Screenshots

N/A

Hosting Information (please complete the following information):

(Bug confirmed on local machine as well)

  • How are you Hosting this: AWS
  • Are you deploying: ECS / Docker
  • Are you using Azure Bot Services: Yes
  • What Client are you using: MSTeams
  • What Node version are you using: v22

Additional context

Workaround: use continueConversation to create a new TurnContext with a correctly-scoped token, and manually set channelData on the synthetic activity (since TeamsInfo.getMember requires it via parseTeamsChannelData, which throws a ZodError if channelData is undefined).

This was working before the migration from botframework-connector / botbuilder to @microsoft/agents-hosting.

Metadata

Metadata

Assignees

Labels

TriageNew issue, yet to be triaged

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions