{"record":{"id":"d2b00dd51fe46c85","repo":"Budibase/budibase","slug":"teams-oauth-token-request-failed-resp-status","errorCode":null,"errorMessage":"Teams OAuth token request failed (${resp.status}): ${await resp.text()}","messagePattern":"Teams OAuth token request failed \\((.+?)\\): (.+?)","errorType":"http","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/server/src/escalation/notifications/ms-teams.ts","lineNumber":75,"sourceCode":"): Promise<string> => {\n  return cache.withCacheWithDynamicTTL(\n    cache.CacheKey.OAUTH2_TOKEN(`teams_${msClientId}_${scope}`),\n    async () => {\n      const resp = await fetch(\n        `https://login.microsoftonline.com/${msTenantId}/oauth2/v2.0/token`,\n        {\n          method: \"POST\",\n          headers: { \"Content-Type\": \"application/x-www-form-urlencoded\" },\n          body: new URLSearchParams({\n            grant_type: \"client_credentials\",\n            client_id: msClientId,\n            client_secret: appPassword,\n            scope,\n          }).toString(),\n        }\n      )\n      if (!resp.ok) {\n        throw new Error(\n          `Teams OAuth token request failed (${resp.status}): ${await resp.text()}`\n        )\n      }\n      const data = (await resp.json()) as {\n        access_token: string\n        expires_in?: number\n      }\n      return { value: data.access_token, ttl: data.expires_in ?? 3600 }\n    }\n  )\n}\n\nconst GRAPH_BASE = \"https://graph.microsoft.com/v1.0\"\n\nconst graphGet = async <T>(url: string, token: string): Promise<T> => {\n  const resp = await fetch(url, {\n    headers: { Authorization: `Bearer ${token}` },\n  })","sourceCodeStart":57,"sourceCodeEnd":93,"githubUrl":"https://github.com/Budibase/budibase/blob/a81a902e9a8fe55b467d106765f6638f12e35c49/packages/server/src/escalation/notifications/ms-teams.ts#L57-L93","documentation":"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.","triggerScenarios":"The POST to https://login.microsoftonline.com/{tenantId}/oauth2/v2.0/token returns a non-2xx status — typically 400/401 from Azure AD.","commonSituations":"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.","solutions":["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.","Check the response body in the error message — Azure returns \"invalid_client\" for bad credentials or \"invalid_scope\" for permission issues; fix accordingly.","Ensure the tenant ID is correct (use the directory/tenant GUID or \"common\") and that admin consent was granted for the required application permissions.","Confirm outbound network access to login.microsoftonline.com from the server (proxy/firewall)."],"exampleFix":"// before\ngetOAuthToken(clientId, staleSecret, \"\", MS_SCOPE_BOT) // 400 invalid_client\n// after\ngetOAuthToken(clientId, rotatedSecret, \"00000000-0000-0000-0000-000000000000\", MS_SCOPE_BOT)","handlingStrategy":"try-catch","validationCode":"if (!clientId || !clientSecret || !tenantId) {\n  throw new Error(\"Teams integration requires appId, appPassword and tenantId\")\n}","typeGuard":null,"tryCatchPattern":"try {\n  token = await getOAuthToken(clientId, secret, tenantId, scope)\n} catch (err) {\n  if (err.message.includes(\"invalid_client\")) {\n    // flag integration credentials as invalid, prompt reconfiguration\n  } else if (err.message.includes(\"invalid_scope\")) {\n    // check admin-consented application permissions\n  } else throw err\n}","preventionTips":["Validate Teams integration credentials (app ID, secret, tenant ID) at save time with a test token request","Rotate client secrets before expiry and track expiration dates","Ensure outbound access to login.microsoftonline.com from the server","Grant admin consent for all required application permissions in Azure AD"],"tags":["oauth","azure-ad","authentication","network","teams"],"backgroundTag":"oauth-token-request-failed","analyzedSha":"a81a902e9a8fe55b467d106765f6638f12e35c49","analyzedAt":"2026-08-29T01:03:10.972Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}