{"record":{"id":"82057c91cb49cb54","repo":"Budibase/budibase","slug":"microsoft-oauth-authorization-failed","errorCode":null,"errorMessage":"Microsoft OAuth authorization failed","messagePattern":"Microsoft OAuth authorization failed","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/server/src/api/controllers/ai/sharepointAuth.ts","lineNumber":121,"sourceCode":"    typeof statePayload?.appId === \"string\" ? statePayload.appId.trim() : \"\"\n  if (\n    !statePayload ||\n    !stateAppId ||\n    statePayload.provider !== MICROSOFT_PROVIDER\n  ) {\n    throw new Error(\"Microsoft OAuth state is invalid or expired\")\n  }\n  const appId = stateAppId\n\n  const oauthError = String(ctx.query.error || \"\").trim()\n  if (oauthError) {\n    const description = String(ctx.query.error_description || \"\").trim()\n    console.error(\"Microsoft OAuth authorization failed\", {\n      appId,\n      error: oauthError,\n      hasDescription: !!description,\n    })\n    throw new Error(\"Microsoft OAuth authorization failed\")\n  }\n\n  const code = String(ctx.query.code || \"\").trim()\n  if (!code) {\n    throw new Error(\n      \"Microsoft OAuth callback is missing the authorization code\"\n    )\n  }\n\n  const { clientId, clientSecret, tenantId } = getMicrosoftConfig()\n  const platformUrl = await configs.getPlatformUrl({ tenantAware: false })\n  const callbackUrl = `${platformUrl}/api/agent/knowledge-sources/sharepoint/callback`\n  const tokenEndpoint = `https://login.microsoftonline.com/${tenantId}/oauth2/v2.0/token`\n\n  const tokenResponse = await fetch(tokenEndpoint, {\n    method: \"POST\",\n    headers: {\n      \"Content-Type\": \"application/x-www-form-urlencoded\",","sourceCodeStart":103,"sourceCodeEnd":139,"githubUrl":"https://github.com/Budibase/budibase/blob/a81a902e9a8fe55b467d106765f6638f12e35c49/packages/server/src/api/controllers/ai/sharepointAuth.ts#L103-L139","documentation":"When Microsoft redirects back with an error query parameter (e.g. access_denied), the controller logs the error and description and throws this generic Error. It abstracts the provider-side failure so the caller only sees that authorization did not succeed.","triggerScenarios":"User denies consent on the Microsoft consent screen; Azure AD returns error=invalid_scope, access_denied, or similar; conditional-access/tenant policies block the app.","commonSituations":"App lacks admin consent for required SharePoint permissions; user cancels the consent dialog; requested scopes (e.g. Sites.ReadWrite.All, offline_access) not granted for the tenant.","solutions":["Check server logs for the accompanying 'Microsoft OAuth authorization failed' entry to see the actual oauthError and description.","Re-run the flow and approve the consent prompt; request admin consent in Azure AD for required scopes.","Reduce/correct requested scopes to those the tenant permits (include offline_access so a refresh token is issued)."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"const oauthError = new URL(callbackUrl).searchParams.get('error')\nif (oauthError) {\n  const desc = new URL(callbackUrl).searchParams.get('error_description')\n  throw new Error(`OAuth rejected by Microsoft: ${oauthError} - ${desc}`)\n}","typeGuard":null,"tryCatchPattern":"try {\n  await completeSharePointAuth(ctx)\n} catch (e) {\n  if (e.message === 'Microsoft OAuth authorization failed') {\n    // inspect server logs for oauthError (e.g. access_denied) and guide user to consent\n  } else throw e\n}","preventionTips":["Request only scopes the tenant will consent to; pre-grant admin consent in Azure AD.","Include offline_access in scopes so refresh tokens are issued.","Check the server console.error log for the real provider error code."],"tags":["oauth","microsoft","consent","sharepoint","authorization"],"backgroundTag":"oauth-authorization-denied","analyzedSha":"a81a902e9a8fe55b467d106765f6638f12e35c49","analyzedAt":"2026-08-29T01:03:10.972Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}