Summary
The msteams plugin bundled with openclaw@2026.4.26 (which pins @openclaw/msteams@2026.4.25) silently drops every inbound Teams message because jwt.verify is not a function. Outbound messages from the bot continue to work, masking the failure — bots appear "online" but never receive user messages.
A fix has already landed on main in commit b3bc60ae40 ("fix(msteams): unwrap jwt runtime deps", 2026-04-27 20:53 UTC), but it was not included in the v2026.4.26 release which was cut a few hours later. So users upgrading to v2026.4.26 still hit this regression.
Reproduction
- Install
openclaw@2026.4.26 (bundles @openclaw/msteams@2026.4.25)
- Configure a fully working Bot Channels / Teams app with valid
appId, appPassword, tenantId, public messaging endpoint
- Send any message to the bot in a Teams DM
Expected: Bot receives the message and an agent reply is dispatched.
Actual: Endpoint returns HTTP 401 silently, no agent run, no log output (even at logging.level=debug). Outbound from the bot still works, so the failure is invisible without packet/inbound instrumentation.
Root cause
In the compiled bundle dist/extensions/msteams/graph-users-Bgd5K8gB.js:
// Compiled (broken):
botFrameworkJwtDepsPromise ??= Promise.all([import("jsonwebtoken"), import("jwks-rsa")])
.then(([jwt, { JwksClient }]) => ({ jwt, JwksClient }));
jsonwebtoken is a CommonJS module. Dynamic import() of a CJS module in Node ESM yields a namespace where verify only exists on .default (while decode is also exposed on the namespace, which is why jwt.decode(token) succeeds and jwt.verify(...) throws TypeError: jwt.verify is not a function).
The try { ... } catch { return false; } in createBotFrameworkJwtValidator.validate then silently swallows the TypeError, returning a falsy validation result and 401-ing the request.
The TS source already has the safe wrappers (loadJsonwebtokenRuntime, loadJwksClientRuntime) introduced in b3bc60ae40, but the plugin shipped at @openclaw/msteams@2026.4.25 (bundled in openclaw@2026.4.26) was built before that commit landed, and the bundler appears to have inlined the destructure rather than calling the helpers.
Diagnostic capture (what we observed)
With local instrumentation patches:
[MSTEAMS_DIAG] inbound POST /api/messages ua=Microsoft-SkypeBotApi (Microsoft-BotFramework/3.0)
[MSTEAMS_DIAG] JWT header={"alg":"RS256","kid":"Pr1J4k5mkxHV31woViVQirfzm5s","typ":"JWT"}
[MSTEAMS_DIAG] JWT claims iss=https://api.botframework.com aud=<our appId> serviceurl=https://smba.trafficmanager.net/amer/<tenant>/ exp=… (valid)
[JWT_DIAG] resolving kid=… from https://login.botframework.com/v1/.well-known/keys
[JWT_DIAG] got public key, length=450
[JWT_DIAG] EXCEPTION during verify: name=TypeError message=jwt.verify is not a function
[MSTEAMS_DIAG] JWT validation FAILED (returned falsy)
Token claims are correct, JWKS fetch is correct, kid resolves, public key extraction works. The verify call itself throws.
Local hot-fix that restored two-way comms
// dist/extensions/msteams/graph-users-Bgd5K8gB.js
botFrameworkJwtDepsPromise ??= Promise.all([import("jsonwebtoken"), import("jwks-rsa")])
.then(([jwtMod, { JwksClient }]) => ({
jwt: jwtMod.default ?? jwtMod,
JwksClient,
}));
After this single-line fix, JWT validation passes, conversations register, agent runs dispatch, and replies flow back to Teams.
Severity
High for any 1:1 or group Teams use case. The failure is invisible (silent 401, no logs even at debug), and the bot looks healthy from the outside because outbound works. We hit ~12 days of dead inbound before pinpointing it.
Suggested actions
- Cut a
v2026.4.27 (or v2026.4.26.1) that includes b3bc60ae40 and republishes @openclaw/msteams with the matching version bump.
- Consider upgrading the silent
catch { return false; } in createBotFrameworkJwtValidator.validate to log the error at warn level — silent JWT validation failures are nearly impossible to diagnose without source patching.
- Add a JWT validation smoke test against a fixture token in CI to catch this regression.
Environment
- openclaw:
2026.4.26
- @openclaw/msteams:
2026.4.25
- Node:
v22.22.0
- OS: Debian 13 (Linux 6.12.74+deb13+1-amd64)
- Bot Framework: standard Microsoft Teams channel via Azure Bot resource (Single Tenant)
Happy to provide a PR for both the source-level guarantee that the bundler can't strip the wrappers, and the catch-block logging improvement, if it would help. Thanks for OpenClaw — once we got past this, two-way comms have been rock solid. 🦞
Summary
The msteams plugin bundled with
openclaw@2026.4.26(which pins@openclaw/msteams@2026.4.25) silently drops every inbound Teams message becausejwt.verify is not a function. Outbound messages from the bot continue to work, masking the failure — bots appear "online" but never receive user messages.A fix has already landed on
mainin commit b3bc60ae40 ("fix(msteams): unwrap jwt runtime deps", 2026-04-27 20:53 UTC), but it was not included in the v2026.4.26 release which was cut a few hours later. So users upgrading to v2026.4.26 still hit this regression.Reproduction
openclaw@2026.4.26(bundles@openclaw/msteams@2026.4.25)appId,appPassword,tenantId, public messaging endpointExpected: Bot receives the message and an agent reply is dispatched.
Actual: Endpoint returns HTTP 401 silently, no agent run, no log output (even at
logging.level=debug). Outbound from the bot still works, so the failure is invisible without packet/inbound instrumentation.Root cause
In the compiled bundle
dist/extensions/msteams/graph-users-Bgd5K8gB.js:jsonwebtokenis a CommonJS module. Dynamicimport()of a CJS module in Node ESM yields a namespace whereverifyonly exists on.default(whiledecodeis also exposed on the namespace, which is whyjwt.decode(token)succeeds andjwt.verify(...)throwsTypeError: jwt.verify is not a function).The
try { ... } catch { return false; }increateBotFrameworkJwtValidator.validatethen silently swallows the TypeError, returning a falsy validation result and 401-ing the request.The TS source already has the safe wrappers (
loadJsonwebtokenRuntime,loadJwksClientRuntime) introduced in b3bc60ae40, but the plugin shipped at @openclaw/msteams@2026.4.25 (bundled in openclaw@2026.4.26) was built before that commit landed, and the bundler appears to have inlined the destructure rather than calling the helpers.Diagnostic capture (what we observed)
With local instrumentation patches:
Token claims are correct, JWKS fetch is correct, kid resolves, public key extraction works. The verify call itself throws.
Local hot-fix that restored two-way comms
After this single-line fix, JWT validation passes, conversations register, agent runs dispatch, and replies flow back to Teams.
Severity
High for any 1:1 or group Teams use case. The failure is invisible (silent 401, no logs even at
debug), and the bot looks healthy from the outside because outbound works. We hit ~12 days of dead inbound before pinpointing it.Suggested actions
v2026.4.27(orv2026.4.26.1) that includes b3bc60ae40 and republishes@openclaw/msteamswith the matching version bump.catch { return false; }increateBotFrameworkJwtValidator.validateto log the error atwarnlevel — silent JWT validation failures are nearly impossible to diagnose without source patching.Environment
2026.4.262026.4.25v22.22.0Happy to provide a PR for both the source-level guarantee that the bundler can't strip the wrappers, and the catch-block logging improvement, if it would help. Thanks for OpenClaw — once we got past this, two-way comms have been rock solid. 🦞