Budibase/budibase · error · Error

Failed to exchange Microsoft OAuth code

Error message

Failed to exchange Microsoft OAuth code

What it means

The token exchange POST to Microsoft's token endpoint returned a non-success status or an error payload; the controller logs status/error details and throws this Error. The code-for-token exchange did not produce usable credentials.

Source

Thrown at packages/server/src/api/controllers/ai/sharepointAuth.ts:158

    },
    body: new URLSearchParams({
      client_id: clientId,
      client_secret: clientSecret,
      grant_type: "authorization_code",
      code,
      redirect_uri: callbackUrl,
      scope: DEFAULT_SCOPE,
    }),
  })
  const tokenPayload = await tokenResponse.json()
  if (!tokenResponse.ok) {
    console.error("Microsoft OAuth token exchange failed", {
      appId,
      status: tokenResponse.status,
      error: tokenPayload?.error,
      hasDescription: !!tokenPayload?.error_description,
    })
    throw new Error("Failed to exchange Microsoft OAuth code")
  }

  const refreshToken = tokenPayload?.refresh_token
  const accessToken = tokenPayload?.access_token
  if (!refreshToken) {
    throw new Error("Microsoft OAuth response did not include a refresh token")
  }
  if (!accessToken) {
    throw new Error("Microsoft OAuth response did not include an access token")
  }

  const expiresIn = Number(tokenPayload?.expires_in || 0)
  const tokenType = tokenPayload?.token_type || "Bearer"
  const bearerToken = `${tokenType} ${accessToken}`
  let account = "unknown"

  try {
    const meResponse = await fetch(

View on GitHub (pinned to a81a902e9a)

Solutions

  1. Check server logs for the 'Microsoft OAuth token exchange failed' entry showing status and error (e.g. invalid_grant, invalid_client).
  2. Ensure the redirect_uri, client_id, and tenant in the token request exactly match the authorize request.
  3. Restart the OAuth flow to get a fresh authorization code; codes cannot be reused.
  4. Verify MICROSOFT_CLIENT_SECRET is current and correctly loaded in the server environment.

Example fix

// before
// token request with redirect_uri that differs from the authorize call
redirect_uri: 'http://localhost:10000/callback'
// after
redirect_uri: 'https://app.example.com/api/ai/sharepoint/callback' // identical to authorize request
Defensive patterns

Strategy: retry

Validate before calling

// ensure a fresh, unused code: start a new flow if the callback has already been processed once

Try / catch

try {
  await completeSharePointAuth(ctx)
} catch (e) {
  if (e.message === 'Failed to exchange Microsoft OAuth code') {
    // check logs for invalid_grant/invalid_client, then restart the OAuth flow with a new code
  } else throw e
}

Prevention

When it happens

Trigger: Authorization code already used or expired (codes are single-use, short-lived); wrong redirect_uri sent in the token request; invalid client secret; tenant mismatch between authorize and token endpoints; network/proxy failure to login.microsoftonline.com.

Common situations: Replaying an auth code after a retry; redirect_uri differing between authorize and token calls (invalid_grant); expired or rotated MICROSOFT_CLIENT_SECRET (invalid_client); clock skew affecting code validity.

Related errors


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