{"record":{"id":"92cfe98e5f388693","repo":"Budibase/budibase","slug":"could-not-refresh-oauth-token","errorCode":null,"errorMessage":"Could not refresh OAuth Token","messagePattern":"Could not refresh OAuth Token","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/backend-core/src/auth/auth.ts","lineNumber":70,"sourceCode":"// Strategies\n_passport.use(new LocalStrategy(local.options, local.authenticate))\n\nasync function refreshOIDCAccessToken(\n  chosenConfig: OIDCInnerConfig,\n  refreshToken: string\n): Promise<RefreshResponse> {\n  const callbackUrl = await oidc.getCallbackUrl()\n  let enrichedConfig: OIDCStrategyConfiguration\n  let strategy: OpenIDConnectStrategy\n\n  try {\n    enrichedConfig = await oidc.fetchStrategyConfig(chosenConfig, callbackUrl)\n    if (!enrichedConfig) {\n      throw new Error(\"OIDC Config contents invalid\")\n    }\n    strategy = await oidc.strategyFactory(enrichedConfig, ssoSaveUserNoOp)\n  } catch (err) {\n    throw new Error(\"Could not refresh OAuth Token\")\n  }\n\n  refresh.use(strategy)\n\n  return new Promise(resolve => {\n    refresh.requestNewAccessToken(\n      ConfigType.OIDC,\n      refreshToken,\n      (err: any, accessToken: string, refreshToken: any, params: any) => {\n        resolve({ err, accessToken, refreshToken, params })\n      }\n    )\n  })\n}\n\nasync function refreshGoogleAccessToken(\n  config: GoogleInnerConfig,\n  refreshToken: any","sourceCodeStart":52,"sourceCodeEnd":88,"githubUrl":"https://github.com/Budibase/budibase/blob/a81a902e9a8fe55b467d106765f6638f12e35c49/packages/backend-core/src/auth/auth.ts#L52-L88","documentation":"Same guard as the drive/list pagination checks: inside fetchSharePointCollection, any '@odata.nextLink' that is not an https URL on graph.microsoft.com/v1.0 causes this HTTPError. It prevents following pagination links that leave the trusted Graph API origin.","triggerScenarios":"A lists/columns/items page response contains '@odata.nextLink' that is relative, http://, on a different hostname/port, or otherwise fails URL parsing against the SHAREPOINT_API_BASE allowlist.","commonSituations":"Proxy or gateway rewriting Graph response bodies; mocked Graph servers in tests returning relative nextLinks; sovereign-cloud endpoints with different hostnames; corrupted response payloads.","solutions":["Route traffic directly to graph.microsoft.com without response-rewriting proxies.","Validate your test/mock fixtures return absolute https://graph.microsoft.com/v1.0/... nextLinks.","If a sovereign cloud is in use, note the allowlist only accepts the global cloud host.","Log the offending nextLink and check it with new URL(link) to see which constraint (protocol/host/port/path) fails."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"const link = payload[\"@odata.nextLink\"]\nif (link && !/^https:\\/\\/graph\\.microsoft\\.com\\/v1\\.0\\//.test(link)) {\n  throw new Error(`Unexpected nextLink host: ${new URL(link, \"https://graph.microsoft.com\").hostname}`)\n}","typeGuard":"const isGraphV1Url = (v: unknown): v is string =>\n  typeof v === \"string\" && (() => { try { const u = new URL(v); return u.protocol === \"https:\" && u.hostname === \"graph.microsoft.com\" && u.pathname.startsWith(\"/v1.0/\") } catch { return false } })()","tryCatchPattern":"try {\n  await listSharePointLists(token, siteId)\n} catch (e) {\n  if (e instanceof Error && e.message === \"Invalid SharePoint pagination URL\") {\n    // inspect proxy/mock layer for rewritten nextLinks\n  } else throw e\n}","preventionTips":["Use absolute graph.microsoft.com/v1.0 nextLinks in any mocked Graph responses.","Avoid middleboxes that modify HTTP response bodies for Graph traffic.","Verify the deployment network's egress path reaches Graph directly."],"tags":["sharepoint","microsoft-graph","pagination","ssrf"],"backgroundTag":"invalid-pagination-url","analyzedSha":"a81a902e9a8fe55b467d106765f6638f12e35c49","analyzedAt":"2026-08-29T01:03:10.972Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}