Skip to content

Teams: support separate graphTenantId for cross-tenant Graph API access#67174

Open
hddevteam wants to merge 6 commits intoopenclaw:mainfrom
hddevteam:teams-thread-mention-context
Open

Teams: support separate graphTenantId for cross-tenant Graph API access#67174
hddevteam wants to merge 6 commits intoopenclaw:mainfrom
hddevteam:teams-thread-mention-context

Conversation

@hddevteam
Copy link
Copy Markdown

Summary

Adds graphTenantId config field (and MSTEAMS_GRAPH_TENANT_ID env var) to the Microsoft Teams provider so deployments where the bot app is registered in one Azure tenant but Teams/M365 data lives in a separate Microsoft 365 tenant can acquire tokens from the correct tenant for each operation.

Problem

In multi-tenant deployments (bot app registered in Azure AD tenant A, Teams data in M365 tenant B), the existing code used the same Bot Framework App instance to acquire both:

  • Bot Framework reply tokens (must use Azure tenant A)
  • Microsoft Graph API tokens for thread context (must use tenant B)

This caused 403 errors on all Graph API calls (ChannelMessage.Read.All, etc.), silently returning no thread context when a bot was @mentioned in a channel thread.

Solution

  • MSTeamsConfig.graphTenantId: new optional config field
  • MSTEAMS_GRAPH_TENANT_ID: env var fallback (same precedence pattern as existing TEAMS_TENANT_ID)
  • monitor.ts: creates a dedicated graphTokenProvider Bot Framework App instance using graphTenantId when it differs from tenantId
  • message-handler.ts: uses effectiveGraphTokenProvider = graphTokenProvider ?? tokenProvider for all Graph API token acquisitions — no behavior change for single-tenant setups
  • graph-thread.ts: removed silent try/catch in fetchChannelMessage so Graph 403s propagate to the Promise.allSettled handler in the message handler instead of returning undefined silently

Configuration

Single-tenant deployments (most users): no change needed.

Cross-tenant deployments — add to openclaw.json:

{
  "providers": {
    "msteams": {
      "tenantId": "<azure-tenant-id>",
      "graphTenantId": "<m365-tenant-id>"
    }
  }
}

Or via environment: MSTEAMS_GRAPH_TENANT_ID=<m365-tenant-id>

Testing

  • All 866 tests pass (pnpm test)
  • pnpm check clean (lint, type-check, import cycles)
  • Config baseline hash regenerated (pnpm config:docs:gen)
  • Manually verified thread context fetching in a cross-tenant Teams deployment

Checklist

  • Tests pass
  • pnpm check clean
  • Config baseline updated
  • CHANGELOG entry added
  • No behavior change for single-tenant setups

Copilot AI review requested due to automatic review settings April 15, 2026 12:36
@openclaw-barnacle openclaw-barnacle Bot added docs Improvements or additions to documentation channel: msteams Channel integration: msteams size: L labels Apr 15, 2026
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented Apr 15, 2026

Greptile Summary

Adds graphTenantId config field and MSTEAMS_GRAPH_TENANT_ID env var to the Microsoft Teams provider, enabling cross-tenant deployments where the bot app registration and the Teams/M365 data live in different Azure tenants. The monitor now creates a dedicated Bot Framework App instance for Graph API token acquisition when the tenant IDs differ, and the message handler uses an effectiveGraphTokenProvider fallback so single-tenant setups are completely unaffected.

All three inline findings are P2 and do not block merge.

Confidence Score: 5/5

Safe to merge; all findings are P2 style/improvement suggestions with no current production breakage.

The cross-tenant token-provider plumbing is logically correct and well-scoped. Single-tenant behavior is unchanged. The three flagged items (error-result caching after removing the silent catch, undocumented federated-auth limitation, missing tests for the new cross-tenant path) are all quality/documentation concerns rather than defects in the changed code path.

extensions/msteams/src/thread-parent-context.ts (error-caching behavior after fetchChannelMessage change), extensions/msteams/src/graph.ts and token.ts (missing test coverage for graphTenantId paths)

Comments Outside Diff (2)

  1. extensions/msteams/src/thread-parent-context.ts, line 86-88 (link)

    P2 Error results no longer cached; persistent 403s will retry on every message

    Before this PR, fetchChannelMessage silently caught errors and returned undefined. fetchParentMessageCached cached that undefined, so repeated calls for the same parent (e.g., a burst of replies) would not re-hit Graph. Now that fetchChannelMessage propagates errors, the await fetchParent(...) on line 86 throws instead of returning undefined, and touchLru is never reached — meaning nothing is cached on failure.

    In environments where Graph is persistently inaccessible (wrong permissions, restricted tenant), every incoming channel thread message will trigger two failing Graph calls (parent + replies) without any backoff or negative-result cache. The test "caches undefined (Graph error) so failures do not re-fetch on burst" in thread-parent-context.test.ts still passes because it injects a mock fetcher that returns undefined — it no longer describes the real behavior of the default fetchChannelMessage.

    Consider wrapping the await fetchParent(...) in a try/catch that stores a sentinel on error so burst retries still hit the cache:

    let message: GraphThreadMessage | undefined;
    try {
      message = await fetchParent(token, groupId, channelId, parentId);
    } catch {
      // Cache the failure so burst retries do not hammer Graph on persistent errors.
      touchLru(parentCache, key, { message: undefined, expiresAt: now + PARENT_CACHE_TTL_MS }, PARENT_CACHE_MAX);
      throw;
    }
    touchLru(parentCache, key, { message, expiresAt: now + PARENT_CACHE_TTL_MS }, PARENT_CACHE_MAX);
    return message;
    Prompt To Fix With AI
    This is a comment left during a code review.
    Path: extensions/msteams/src/thread-parent-context.ts
    Line: 86-88
    
    Comment:
    **Error results no longer cached; persistent 403s will retry on every message**
    
    Before this PR, `fetchChannelMessage` silently caught errors and returned `undefined`. `fetchParentMessageCached` cached that `undefined`, so repeated calls for the same parent (e.g., a burst of replies) would not re-hit Graph. Now that `fetchChannelMessage` propagates errors, the `await fetchParent(...)` on line 86 throws instead of returning `undefined`, and `touchLru` is never reached — meaning nothing is cached on failure.
    
    In environments where Graph is persistently inaccessible (wrong permissions, restricted tenant), every incoming channel thread message will trigger two failing Graph calls (parent + replies) without any backoff or negative-result cache. The test `"caches undefined (Graph error) so failures do not re-fetch on burst"` in `thread-parent-context.test.ts` still passes because it injects a mock fetcher that returns `undefined` — it no longer describes the real behavior of the default `fetchChannelMessage`.
    
    Consider wrapping the `await fetchParent(...)` in a try/catch that stores a sentinel on error so burst retries still hit the cache:
    
    ```ts
    let message: GraphThreadMessage | undefined;
    try {
      message = await fetchParent(token, groupId, channelId, parentId);
    } catch {
      // Cache the failure so burst retries do not hammer Graph on persistent errors.
      touchLru(parentCache, key, { message: undefined, expiresAt: now + PARENT_CACHE_TTL_MS }, PARENT_CACHE_MAX);
      throw;
    }
    touchLru(parentCache, key, { message, expiresAt: now + PARENT_CACHE_TTL_MS }, PARENT_CACHE_MAX);
    return message;
    ```
    
    How can I resolve this? If you propose a fix, please make it concise.
  2. extensions/msteams/src/graph.ts, line 217-229 (link)

    P2 graphTenantId path untested; new App instance created on every call

    loadMSTeamsSdkWithAuth(graphCreds) is called on every invocation of resolveGraphToken. For the cross-tenant path (graphTenantId !== tenantId), this instantiates a second Bot Framework App per call. For CLI commands that call resolveGraphToken in a loop this can be expensive.

    Additionally, the new graphCreds substitution has no test coverage in graph.test.ts — neither the token acquisition with graphTenantId nor the fallback when graphTenantId === tenantId. Similarly, token.test.ts has no cases that exercise graphTenantId propagation through resolveMSTeamsCredentials. For a feature that changes which OAuth tenant is used to acquire tokens, adding at least happy-path tests would help prevent regressions.

    Prompt To Fix With AI
    This is a comment left during a code review.
    Path: extensions/msteams/src/graph.ts
    Line: 217-229
    
    Comment:
    **`graphTenantId` path untested; new `App` instance created on every call**
    
    `loadMSTeamsSdkWithAuth(graphCreds)` is called on every invocation of `resolveGraphToken`. For the cross-tenant path (`graphTenantId !== tenantId`), this instantiates a second Bot Framework `App` per call. For CLI commands that call `resolveGraphToken` in a loop this can be expensive.
    
    Additionally, the new `graphCreds` substitution has no test coverage in `graph.test.ts` — neither the token acquisition with `graphTenantId` nor the fallback when `graphTenantId === tenantId`. Similarly, `token.test.ts` has no cases that exercise `graphTenantId` propagation through `resolveMSTeamsCredentials`. For a feature that changes which OAuth tenant is used to acquire tokens, adding at least happy-path tests would help prevent regressions.
    
    How can I resolve this? If you propose a fix, please make it concise.
Prompt To Fix All With AI
This is a comment left during a code review.
Path: extensions/msteams/src/thread-parent-context.ts
Line: 86-88

Comment:
**Error results no longer cached; persistent 403s will retry on every message**

Before this PR, `fetchChannelMessage` silently caught errors and returned `undefined`. `fetchParentMessageCached` cached that `undefined`, so repeated calls for the same parent (e.g., a burst of replies) would not re-hit Graph. Now that `fetchChannelMessage` propagates errors, the `await fetchParent(...)` on line 86 throws instead of returning `undefined`, and `touchLru` is never reached — meaning nothing is cached on failure.

In environments where Graph is persistently inaccessible (wrong permissions, restricted tenant), every incoming channel thread message will trigger two failing Graph calls (parent + replies) without any backoff or negative-result cache. The test `"caches undefined (Graph error) so failures do not re-fetch on burst"` in `thread-parent-context.test.ts` still passes because it injects a mock fetcher that returns `undefined` — it no longer describes the real behavior of the default `fetchChannelMessage`.

Consider wrapping the `await fetchParent(...)` in a try/catch that stores a sentinel on error so burst retries still hit the cache:

```ts
let message: GraphThreadMessage | undefined;
try {
  message = await fetchParent(token, groupId, channelId, parentId);
} catch {
  // Cache the failure so burst retries do not hammer Graph on persistent errors.
  touchLru(parentCache, key, { message: undefined, expiresAt: now + PARENT_CACHE_TTL_MS }, PARENT_CACHE_MAX);
  throw;
}
touchLru(parentCache, key, { message, expiresAt: now + PARENT_CACHE_TTL_MS }, PARENT_CACHE_MAX);
return message;
```

How can I resolve this? If you propose a fix, please make it concise.

---

This is a comment left during a code review.
Path: extensions/msteams/src/token.ts
Line: 95-98

Comment:
**`graphTenantId` silently dropped for federated auth**

`graphTenantId` is resolved from config/env for both auth types but is only placed on the returned `MSTeamsSecretCredentials` struct. For `authType === "federated"`, the value is silently discarded and `MSTeamsFederatedCredentials` has no `graphTenantId` field, so `monitor.ts` and `graph.ts` will never use it regardless of what the operator configures.

The docs (`docs/channels/msteams.md`) and the `MSTeamsConfig` JSDoc on `graphTenantId` should note that this field is only effective when `authType` is `"secret"` (the default). Setting `MSTEAMS_GRAPH_TENANT_ID` with a federated identity setup will have no effect.

How can I resolve this? If you propose a fix, please make it concise.

---

This is a comment left during a code review.
Path: extensions/msteams/src/graph.ts
Line: 217-229

Comment:
**`graphTenantId` path untested; new `App` instance created on every call**

`loadMSTeamsSdkWithAuth(graphCreds)` is called on every invocation of `resolveGraphToken`. For the cross-tenant path (`graphTenantId !== tenantId`), this instantiates a second Bot Framework `App` per call. For CLI commands that call `resolveGraphToken` in a loop this can be expensive.

Additionally, the new `graphCreds` substitution has no test coverage in `graph.test.ts` — neither the token acquisition with `graphTenantId` nor the fallback when `graphTenantId === tenantId`. Similarly, `token.test.ts` has no cases that exercise `graphTenantId` propagation through `resolveMSTeamsCredentials`. For a feature that changes which OAuth tenant is used to acquire tokens, adding at least happy-path tests would help prevent regressions.

How can I resolve this? If you propose a fix, please make it concise.

Reviews (1): Last reviewed commit: "Teams: support separate graphTenantId fo..." | Re-trigger Greptile

Comment thread extensions/msteams/src/token.ts
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds cross-tenant Microsoft Graph token acquisition support for the bundled Microsoft Teams integration, so Bot Framework reply tokens and Graph API tokens can be issued from different Azure tenants when needed.

Changes:

  • Introduces graphTenantId / MSTEAMS_GRAPH_TENANT_ID and wires a dedicated Graph token provider into Teams runtime.
  • Improves channel thread context behavior (thread root resolution, mention-only thread replies, Graph error propagation, and an in-memory fallback cache).
  • Hardens Teams webhook JSON parsing by repairing invalid escape sequences; extends runtime logging to forward structured meta.

Reviewed changes

Copilot reviewed 20 out of 20 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
src/plugins/runtime/runtime-logging.ts Passes meta through runtime logger methods.
src/plugins/runtime/runtime-logging.test.ts Adds tests ensuring logger meta is forwarded and shouldLogVerbose is re-exported.
src/plugin-sdk/msteams.ts Re-exports resolveThreadSessionKeys via the Teams plugin SDK surface.
src/config/zod-schema.providers-core.ts Adds graphTenantId to the Teams config schema.
src/config/types.msteams.ts Documents and types the new graphTenantId config field.
extensions/msteams/src/token.ts Resolves graphTenantId from config/env and returns it in secret credentials.
extensions/msteams/src/thread-message-cache.ts Adds a simple in-memory per-thread message cache with TTL.
extensions/msteams/src/sdk-types.ts Extends activity typing to include team.aadGroupId.
extensions/msteams/src/monitor.ts Creates a dedicated Graph token provider when graphTenantId differs; switches webhook parsing to raw + repair middleware.
extensions/msteams/src/monitor.lifecycle.test.ts Updates Express mocking for raw() and middleware count/order assertions.
extensions/msteams/src/monitor-handler/message-handler.ts Uses graph token provider, adds mention-only thread handling, thread root resolution, and cache-based context fallback.
extensions/msteams/src/monitor-handler/message-handler.thread-parent.test.ts Adds coverage for mention-only thread invocation and cache fallback behaviors.
extensions/msteams/src/monitor-handler/message-handler.test-support.ts Extends test logger stub with warn.
extensions/msteams/src/monitor-handler.types.ts Adds optional graphTokenProvider dependency.
extensions/msteams/src/graph.ts Uses graphTenantId when resolving app-only Graph tokens.
extensions/msteams/src/graph-thread.ts Removes silent error swallowing in fetchChannelMessage.
extensions/msteams/src/graph-thread.test.ts Updates test to assert errors propagate.
extensions/msteams/src/tests/monitor-json-repair.test.ts Adds regression tests for the JSON repair behavior.
docs/channels/msteams.md Documents mention-only thread behavior and Graph permission requirement.
CHANGELOG.md Adds changelog entry for the new cross-tenant Graph token acquisition support.

Comment thread extensions/msteams/src/thread-message-cache.ts Outdated
Comment thread extensions/msteams/src/graph-thread.ts
Comment thread docs/channels/msteams.md Outdated
Comment thread extensions/msteams/src/token.ts
Comment thread extensions/msteams/src/monitor-handler/message-handler.ts Outdated
Comment thread extensions/msteams/src/thread-message-cache.ts Outdated
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: b782db1718

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread extensions/msteams/src/graph.ts Outdated
@hddevteam hddevteam force-pushed the teams-thread-mention-context branch from b782db1 to 38defac Compare April 19, 2026 11:54
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 38defaca07

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread extensions/msteams/src/monitor-handler/message-handler.ts Outdated
@vincentkoc vincentkoc added the triage: dirty-candidate Candidate: broad unrelated surfaces; may need splitting or cleanup. label Apr 26, 2026
@clawsweeper
Copy link
Copy Markdown
Contributor

clawsweeper Bot commented Apr 28, 2026

Codex review: found issues before merge.

What this changes:

The PR adds channels.msteams.graphTenantId and MSTEAMS_GRAPH_TENANT_ID, routes Teams Graph token acquisition through a tenant-specific provider, updates Graph thread error/cache behavior, and refreshes docs, plugin metadata, config metadata, tests, and changelog.

Maintainer follow-up before merge:

This is an active contributor PR in Teams auth and secret-handling code with a concrete security finding, so the next action is maintainer review/requested author fixes rather than an automated replacement or cleanup close.

Security review:

Security review needs attention: The diff introduces no third-party code or CI/package execution changes, but it does retain a plaintext Teams client secret in a module-level cache key.

Review findings:

  • [P2] Avoid caching raw Teams client secrets — extensions/msteams/src/graph.ts:49
  • [P3] Add required changelog attribution — CHANGELOG.md:13
Review details

Best possible solution:

Land a narrow Teams plugin change that keeps Bot Framework reply tokens on the bot tenant, uses graphTenantId only for Graph app-only token acquisition, avoids raw secret retention in cache keys, and keeps config schema, docs, generated metadata, tests, and changelog attribution aligned.

Do we have a high-confidence way to reproduce the issue?

Yes for the static behavior: current main has no graphTenantId config/env surface and mints Graph tokens through the same Teams app provider used for Bot Framework replies. A live reproduction would require a split Azure/M365 tenant setup, which was not available in this read-only review.

Is this the best way to solve the issue?

No, not merge-ready as written. The split-provider design is the narrow right direction, but the cache key should not contain a raw client secret and the changelog needs the required attribution before merge.

Full review comments:

  • [P2] Avoid caching raw Teams client secrets — extensions/msteams/src/graph.ts:49
    buildGraphTokenProviderCacheKey stringifies creds.appPassword into the module-level cache key. That keeps a plaintext Azure client secret in memory beyond immediate credential resolution; use a non-secret discriminator or one-way fingerprint instead.
    Confidence: 0.84
  • [P3] Add required changelog attribution — CHANGELOG.md:13
    The new user-facing Microsoft Teams changelog entry does not include the repo-required Thanks @... credit. Add the contributor or reporter attribution to the same single-line entry before merge.
    Confidence: 0.96

Overall correctness: patch is incorrect
Overall confidence: 0.84

Security concerns:

  • [low] Raw client secret retained in cache key — extensions/msteams/src/graph.ts:49
    The Graph token-provider cache key includes creds.appPassword, so a plaintext Azure client secret is stored in the module-level cache key for the cache lifetime. Use a non-secret key component or a one-way fingerprint.
    Confidence: 0.84

Acceptance criteria:

  • pnpm test extensions/msteams/src/token.test.ts extensions/msteams/src/graph.test.ts extensions/msteams/src/graph-thread.test.ts extensions/msteams/src/thread-parent-context.test.ts
  • pnpm exec oxfmt --check --threads=1 extensions/msteams/src/graph.ts extensions/msteams/src/token.ts extensions/msteams/src/monitor.ts extensions/msteams/src/monitor-handler/message-handler.ts extensions/msteams/src/thread-parent-context.ts docs/channels/msteams.md src/config/types.msteams.ts src/config/zod-schema.providers-core.ts
  • pnpm config:docs:gen/check
  • pnpm check:changed

What I checked:

  • Current main lacks requested surface: Exact search found no graphTenantId, MSTEAMS_GRAPH_TENANT_ID, graphTokenProvider, or effectiveGraphTokenProvider symbols on current main, while related Teams Graph helpers are present. (a256745323ab)
  • Current config type has no Graph tenant override: MSTeamsConfig defines tenantId and then authType; no Graph-specific tenant field exists on current main. (src/config/types.msteams.ts:95, a256745323ab)
  • Current schema rejects graphTenantId: The Teams Zod schema accepts tenantId and then authType; graphTenantId is absent from validation. (src/config/zod-schema.providers-core.ts:1571, a256745323ab)
  • Current Graph token path uses the normal Teams credentials: resolveGraphToken loads the Teams SDK with creds directly and creates a token provider from that same app before requesting the Graph token. (extensions/msteams/src/graph.ts:213, a256745323ab)
  • Current thread context uses Bot Framework token provider: Thread context fetching calls tokenProvider.getAccessToken("https://graph.microsoft.com") with no separate Graph provider dependency. (extensions/msteams/src/monitor-handler/message-handler.ts:620, a256745323ab)
  • PR implements the requested split-tenant path: The latest PR diff adds config/docs/env metadata, carries graphTenantId through secret and federated credentials, builds separate Graph token providers, and wires the handler to use graphTokenProvider when present. (extensions/msteams/src/monitor.ts:239, a07328fe0191)

Likely related people:

  • steipete: Recent remote history shows multiple May/April 2026 refactors touching the Teams Graph/token and message-handler paths, and local blame for the current checked-out Teams files points to recent maintainer commits. (role: recent maintainer; confidence: high; commits: 3f002b10d281, ffe67e9cdc9e, 02ebac6250bf; files: extensions/msteams/src/graph.ts, extensions/msteams/src/token.ts, extensions/msteams/src/monitor-handler/message-handler.ts)
  • HDYA: Introduced Microsoft Teams federated credential support, which is directly adjacent to the PR's secret/federated graphTenantId credential routing. (role: introduced related auth behavior; confidence: medium; commits: 26f633b604fd; files: extensions/msteams/src/token.ts, extensions/msteams/src/graph.ts, src/config/types.msteams.ts)
  • sudie-codes: Recent Teams Graph action, delegated auth, pagination, and group-management commits changed the Graph token/helper area this PR extends. (role: Graph and delegated-auth contributor; confidence: medium; commits: 355794c24a39, f71ee71787c7, 0f192710924f; files: extensions/msteams/src/graph.ts, extensions/msteams/src/token.ts, extensions/msteams/src/monitor-handler/message-handler.ts)
  • BradGroux: Auth/config history and the related Microsoft tracker show Brad Groux repeatedly involved in Teams and Microsoft ecosystem routing, including co-authorship on federated/Graph changes and direct Teams config commits. (role: adjacent Microsoft Teams maintainer; confidence: medium; commits: 26f633b604fd, 355794c24a39, fce81fccd859; files: src/config/types.msteams.ts, extensions/msteams/src/graph.ts, extensions/msteams/src/token.ts)

Remaining risk / open question:

  • The latest PR diff still retains appPassword in the Graph token-provider cache key, which keeps a plaintext client secret in memory longer than necessary.
  • The user-facing changelog entry is missing the repo-required non-bot contributor attribution.
  • No live Azure split-tenant Teams environment was exercised during this read-only review; the need and fix direction are supported by static code paths and the PR author's manual verification claim.

Codex review notes: model gpt-5.5, reasoning high; reviewed against a256745323ab.

@hddevteam hddevteam force-pushed the teams-thread-mention-context branch 2 times, most recently from 0eb41ae to 6c36b1f Compare April 29, 2026 01:04
Ming and others added 6 commits April 29, 2026 09:14
Add `graphTenantId` config field (and `MSTEAMS_GRAPH_TENANT_ID` env var)
so the bot can acquire Bot Framework reply tokens and Graph API tokens
from different Azure tenants. This enables thread context fetching when
the bot app is registered in one Azure tenant but Teams/M365 data lives
in a separate Microsoft 365 tenant.

Changes:
- `MSTeamsConfig.graphTenantId`: new optional field in config type + zod schema
- `MSTeamsSecretCredentials.graphTenantId`: carry through credential resolution
- `token.ts`: resolve graphTenantId from config or MSTEAMS_GRAPH_TENANT_ID env
- `graph.ts`: use graphTenantId tenant when acquiring Graph-only token
- `monitor.ts`: create dedicated graphTokenProvider App when tenants differ
- `monitor-handler.types.ts`: add optional graphTokenProvider to handler deps
- `message-handler.ts`: use effectiveGraphTokenProvider for thread context calls
- `graph-thread.ts`: remove silent error catch in fetchChannelMessage so 403s
  surface to the caller's Promise.allSettled handler instead of silently
  returning undefined

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

channel: msteams Channel integration: msteams docs Improvements or additions to documentation size: M triage: dirty-candidate Candidate: broad unrelated surfaces; may need splitting or cleanup.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants