-
-
Notifications
You must be signed in to change notification settings - Fork 69.5k
[Bug]: Gateway JWT middleware blocks Bot Framework webhooks in msteams plugin #14436
Description
Summary
The OpenClaw gateway applies JWT authentication middleware globally to all routes, which blocks legitimate Microsoft Bot Framework webhooks at /api/messages. This prevents the msteams plugin from receiving webhooks from Azure Bot Service.
Environment
- OpenClaw version: 2026.2.9
- Node.js: v24.13.0
- OS: Windows 10.0.26100 (x64)
- Plugin: msteams (built-in)
Steps to Reproduce
- Configure msteams plugin with valid Azure Bot credentials:
"channels": { "msteams": { "enabled": true, "appId": "<valid-app-id>", "appPassword": "<valid-password>", "tenantId": "<valid-tenant-id>" } }
Start OpenClaw gateway (msteams plugin creates webhook server on port 3978)
Configure Azure Bot Service messaging endpoint: https:///api/messages
Send a test message to the bot in Microsoft Teams
Expected Behavior
- Bot Framework sends webhook with Microsoft's JWT token
- msteams plugin's Bot Framework adapter validates the Microsoft JWT
- Webhook is processed successfully
- Bot responds in Teams
Actual Behavior
- Bot Framework sends webhook with Microsoft's JWT token
- OpenClaw gateway JWT middleware intercepts the request first
- Gateway expects OpenClaw's own JWT token format
- Request is rejected with: {"jwt-auth-error":"authorization header not found"} (401)
- Webhook never reaches the Bot Framework adapter
- Bot does not respond
Log evidence:
$ curl -X POST http://localhost:3978/api/messages -H "Content-Type: application/json" -d "{}" {"jwt-auth-error":"authorization header not found"}
Root Cause
The gateway applies JWT authentication middleware to all routes on the msteams webhook server. The Bot Framework adapter at /api/messages has its own JWT validation logic (validates Microsoft-signed tokens), but the OpenClaw JWT middleware intercepts requests before they reach the adapter.
Two incompatible JWT systems:
- OpenClaw Gateway JWT - Internal authentication for OpenClaw API endpoints
- Bot Framework JWT - Microsoft's authentication for webhook callbacks
The /api/messages endpoint should bypass OpenClaw JWT and only use Bot Framework JWT validation.
Workaround
Created a reverse proxy that strips OpenClaw JWT requirements:
// Proxy: localhost:4000 -> localhost:3978
app.all('/api/messages', async (req, res) => {
const headers = { ...req.headers };
delete headers['x-openclaw-token'];
const response = await axios({
method: req.method,
url: 'http://localhost:3978/api/messages',
data: req.body,
headers
});
res.status(response.status).send(response.data);
});
Architecture with workaround:
Bot Service → Cloudflare Tunnel → Proxy (4000) → OpenClaw msteams (3978)
↑ JWT bypass here
Suggested Fix
The msteams plugin should exclude /api/messages from OpenClaw JWT middleware:
// Option 1: Exclude path from gateway JWT
app.use((req, res, next) => {
if (req.path === '/api/messages') {
return next(); // Skip OpenClaw JWT for Bot Framework endpoint
}
openclawJwtAuth(req, res, next); // Apply JWT to other routes
});
app.post('/api/messages', adapter.process); // Bot Framework handles JWT here
// Option 2: Register route BEFORE middleware
app.post('/api/messages', adapter.process); // Register first
app.use(openclawJwtAuth); // Apply JWT to everything else
The Bot Framework adapter already validates Microsoft JWTs internally via ConfigurationBotFrameworkAuthentication, so no additional authentication is needed on this route.
Additional Context
Bot Framework JWT validation (already built-in):
import { CloudAdapter, ConfigurationBotFrameworkAuthentication } from '@microsoft/agents-hosting';
const auth = new ConfigurationBotFrameworkAuthentication({
MicrosoftAppId: config.appId,
MicrosoftAppPassword: config.appPassword,
MicrosoftAppTenantId: config.tenantId
});
const adapter = new CloudAdapter(auth);
// Adapter validates Microsoft's JWT automatically in adapter.process()
This is a blocker for Teams integration - the bot cannot receive any messages from Azure Bot Service without bypassing OpenClaw's gateway entirely.