Budibase/budibase · error · Error

Teams OAuth token request failed (${resp.status}): ${await r

Error message

Teams OAuth token request failed (${resp.status}): ${await resp.text()}

What it means

getOAuthToken performs an Azure AD client-credentials token request against login.microsoftonline.com using the Teams integration's appId/appPassword. If the HTTP response is not ok, it throws with the status and the raw response body so the Azure AD error (invalid_client, invalid scope, etc.) is visible. Called through the token getter used by both Bot Framework and Graph flows.

Source

Thrown at packages/server/src/escalation/notifications/ms-teams.ts:75

): Promise<string> => {
  return cache.withCacheWithDynamicTTL(
    cache.CacheKey.OAUTH2_TOKEN(`teams_${msClientId}_${scope}`),
    async () => {
      const resp = await fetch(
        `https://login.microsoftonline.com/${msTenantId}/oauth2/v2.0/token`,
        {
          method: "POST",
          headers: { "Content-Type": "application/x-www-form-urlencoded" },
          body: new URLSearchParams({
            grant_type: "client_credentials",
            client_id: msClientId,
            client_secret: appPassword,
            scope,
          }).toString(),
        }
      )
      if (!resp.ok) {
        throw new Error(
          `Teams OAuth token request failed (${resp.status}): ${await resp.text()}`
        )
      }
      const data = (await resp.json()) as {
        access_token: string
        expires_in?: number
      }
      return { value: data.access_token, ttl: data.expires_in ?? 3600 }
    }
  )
}

const GRAPH_BASE = "https://graph.microsoft.com/v1.0"

const graphGet = async <T>(url: string, token: string): Promise<T> => {
  const resp = await fetch(url, {
    headers: { Authorization: `Bearer ${token}` },
  })

View on GitHub (pinned to a81a902e9a)

Solutions

  1. Verify the Teams integration's app ID, app password (client secret) and tenant ID match an active Azure AD app registration; regenerate the secret if it expired.
  2. Check the response body in the error message — Azure returns "invalid_client" for bad credentials or "invalid_scope" for permission issues; fix accordingly.
  3. Ensure the tenant ID is correct (use the directory/tenant GUID or "common") and that admin consent was granted for the required application permissions.
  4. Confirm outbound network access to login.microsoftonline.com from the server (proxy/firewall).

Example fix

// before
getOAuthToken(clientId, staleSecret, "", MS_SCOPE_BOT) // 400 invalid_client
// after
getOAuthToken(clientId, rotatedSecret, "00000000-0000-0000-0000-000000000000", MS_SCOPE_BOT)
Defensive patterns

Strategy: try-catch

Validate before calling

if (!clientId || !clientSecret || !tenantId) {
  throw new Error("Teams integration requires appId, appPassword and tenantId")
}

Try / catch

try {
  token = await getOAuthToken(clientId, secret, tenantId, scope)
} catch (err) {
  if (err.message.includes("invalid_client")) {
    // flag integration credentials as invalid, prompt reconfiguration
  } else if (err.message.includes("invalid_scope")) {
    // check admin-consented application permissions
  } else throw err
}

Prevention

When it happens

Trigger: The POST to https://login.microsoftonline.com/{tenantId}/oauth2/v2.0/token returns a non-2xx status — typically 400/401 from Azure AD.

Common situations: Wrong or missing msTenantId (e.g. empty because the agent's Teams integration has no tenant configured); wrong appPassword/client secret or a secret that expired or was rotated; app registration deleted; wrong scope requested or permissions not consented by admin; network/proxy blocking login.microsoftonline.com.

Related errors


AI-assisted analysis of Budibase/budibase@a81a902e9a (2026-08-29). Data as JSON: /api/errors/d2b00dd51fe46c85. Report an issue: GitHub.