Channels
Msteams Jwt Fix
Hot-patch for OpenClaw msteams plugin JWT validation regression in v2026.4.25/v2026.4.26 (silently 401s every inbound Teams message). See upstream issue openclaw/openclaw#73754.
Configuration Example
// Broken — jwt.verify is undefined here because jsonwebtoken is CommonJS
botFrameworkJwtDepsPromise ??= Promise.all([import("jsonwebtoken"), import("jwks-rsa")])
.then(([jwt, { JwksClient }]) => ({ jwt, JwksClient }));
README
# openclaw-msteams-jwt-fix
A small hot-patch for the [OpenClaw](https://github.com/openclaw/openclaw) `@openclaw/msteams` plugin shipped in `v2026.4.25` and bundled in `[email protected]`. These versions silently drop **every inbound Microsoft Teams message** because of a CommonJS/ESM interop regression in the bundled JWT validator.
> **Symptoms:** Outbound bot messages work fine. Inbound messages silently 401 with no log output (even at `logging.level=debug`). The bot looks healthy from the outside but never receives anything.
Upstream tracking: **[openclaw/openclaw#73754](https://github.com/openclaw/openclaw/issues/73754)**.
The upstream fix landed on `main` in commit `b3bc60ae40` ("fix(msteams): unwrap jwt runtime deps", 2026-04-27) but missed the cut for `v2026.4.26`. Until a fixed release ships, run the patcher in this repo against any OpenClaw install on the affected versions.
## What the bug looks like
In the compiled bundle `dist/extensions/msteams/graph-users-Bgd5K8gB.js`:
```js
// Broken — jwt.verify is undefined here because jsonwebtoken is CommonJS
botFrameworkJwtDepsPromise ??= Promise.all([import("jsonwebtoken"), import("jwks-rsa")])
.then(([jwt, { JwksClient }]) => ({ jwt, JwksClient }));
```
When Microsoft sends a signed JWT, `jwtValidator.validate(...)` throws `TypeError: jwt.verify is not a function`, which is silently swallowed by an empty `catch { return false; }`. The endpoint returns 401, no logs are emitted, and the conversation never registers.
## What the patch does
A single, surgical replacement in the compiled file:
```js
// Fixed — unwraps the .default export when present, just like the TS source does
botFrameworkJwtDepsPromise ??= Promise.all([import("jsonwebtoken"), import("jwks-rsa")])
.then(([jwtMod, { JwksClient }]) => ({
jwt: jwtMod.default ?? jwtMod,
JwksClient,
}));
```
That's it. No other behavior changes. The patch is idempotent — running it twice is safe; running it on an already-fixed install is a no-op.
## Usage
```bash
# Locate your OpenClaw msteams plugin directory and run:
node patch.js /path/to/openclaw/dist/extensions/msteams
# Or point it at the parent openclaw install and let it find msteams:
node patch.js /home/youruser/.npm-global/lib/node_modules/openclaw
# After patching, restart the gateway:
systemctl --user restart openclaw-gateway
# or whichever service manager you use
```
The script prints what it found, what it changed, and whether a backup was written.
### Verify it worked
After restarting the gateway, send any Teams DM to your bot. If two-way comms is restored, the conversation will be recorded in `~/.openclaw/msteams-conversations.json` (the `lastSeenAt` timestamp will update) and the agent will dispatch a reply.
If you want hard proof before testing in Teams, the patcher exits non-zero when the file is unrecognized or already patched, so you can chain it in scripts safely.
## Affected versions
| openclaw | @openclaw/msteams | inbound Teams works? |
|---|---|---|
| ≤ 2026.4.24 | ≤ 2026.4.24 | ✅ (pre-regression) |
| 2026.4.25 | 2026.4.25 | ❌ broken |
| 2026.4.26 | 2026.4.25 (bundled) | ❌ broken |
| ≥ 2026.4.27 (unreleased) | ≥ 2026.4.26 | ✅ (fix included) |
## Safety notes
- Always backed up: the patcher writes `<file>.bak-<timestamp>` before modifying.
- Doesn't touch your config, secrets, or state — purely modifies the plugin's bundled code.
- Works on `[email protected]` installed via `npm i -g openclaw` or via plugin runtime deps.
## License
MIT — see [LICENSE](./LICENSE).
## Credit
Diagnosed and patched while debugging a 12-day Teams inbound outage on a production BlueCircuit.ai bot. The OpenClaw maintainers had already landed the fix upstream in `b3bc60ae` — this repo just bridges the gap until a fixed release ships.
🦞
channels
Comments
Sign in to leave a comment