Description
When using a SingleTenant Azure Bot with the MS Teams channel, incoming webhook requests from Azure Bot Service are rejected with 401 Unauthorized. This affects all new bot deployments since Microsoft deprecated MultiTenant bot creation after 2025-07-31.
Root Cause
Two issues in the JWT validation chain:
1. Issuer mismatch in validateIssuer() (jwt-validator)
The allowedTenantIds issuer check only accepts:
https://login.microsoftonline.com/{tenantId}/
But SingleTenant Bot Framework tokens use the v1 issuer:
https://sts.windows.net/{tenantId}/
2. Audience mismatch in entraValidator (graph-users / msteams extension)
The entraValidator in createBotFrameworkJwtValidator() does not include https://api.botframework.com in its accepted audiences. The default audience list is [clientId, "api://botid-{clientId}", "api://{clientId}"], but Bot Framework tokens always have aud: "https://api.botframework.com".
Error Flow
1. botFrameworkValidator -> SigningKeyNotFoundError
(key not at login.botframework.com, signed with Azure AD keys)
2. entraValidator -> finds key at login.microsoftonline.com/common
-> signature valid
-> issuer check FAILS (sts.windows.net not accepted)
-> OR audience check FAILS (api.botframework.com not in list)
Workaround
Patch two files in the container:
jwt-validator-*.js - extend issuer check:
// Before:
if (!allowedTenantIds.some((tenantId) => iss.startsWith(`https://login.microsoftonline.com/${tenantId}/`)))
// After:
if (!allowedTenantIds.some((tenantId) => iss.startsWith(`https://login.microsoftonline.com/${tenantId}/`) || iss.startsWith(`https://sts.windows.net/${tenantId}/`)))
graph-users-*.js - add BF audience to entraValidator:
const entraValidator = new JwtValidator({
clientId: creds.appId,
tenantId: creds.tenantId,
audience: ["https://api.botframework.com"], // ADD THIS
validateIssuer: { allowedTenantIds: [creds.tenantId] },
jwksUriOptions: { type: "uri", uri: "https://login.microsoftonline.com/common/discovery/v2.0/keys" }
});
Environment
- OpenClaw version: 2026.4.9 (Docker image
ghcr.io/openclaw/openclaw:latest)
- Azure Bot: SingleTenant (
msaAppType: "SingleTenant")
- Channel: MS Teams
- Azure AD Tenant: Single-org (AzureADMyOrg)
Expected Behavior
SingleTenant bot tokens should be accepted by the msteams channel JWT validator, as the docs state SingleTenant is the recommended approach.
Description
When using a SingleTenant Azure Bot with the MS Teams channel, incoming webhook requests from Azure Bot Service are rejected with
401 Unauthorized. This affects all new bot deployments since Microsoft deprecated MultiTenant bot creation after 2025-07-31.Root Cause
Two issues in the JWT validation chain:
1. Issuer mismatch in
validateIssuer()(jwt-validator)The
allowedTenantIdsissuer check only accepts:But SingleTenant Bot Framework tokens use the v1 issuer:
2. Audience mismatch in
entraValidator(graph-users/ msteams extension)The
entraValidatorincreateBotFrameworkJwtValidator()does not includehttps://api.botframework.comin its accepted audiences. The default audience list is[clientId, "api://botid-{clientId}", "api://{clientId}"], but Bot Framework tokens always haveaud: "https://api.botframework.com".Error Flow
Workaround
Patch two files in the container:
jwt-validator-*.js- extend issuer check:graph-users-*.js- add BF audience to entraValidator:Environment
ghcr.io/openclaw/openclaw:latest)msaAppType: "SingleTenant")Expected Behavior
SingleTenant bot tokens should be accepted by the msteams channel JWT validator, as the docs state SingleTenant is the recommended approach.