{"record":{"id":"c9def230166ef8c3","repo":"danny-avila/LibreChat","slug":"failed-to-obtain-sharepoint-access-token","errorCode":null,"errorMessage":"Failed to obtain SharePoint access token","messagePattern":"Failed to obtain SharePoint access token","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"client/src/hooks/Files/useSharePointDownload.ts","lineNumber":56,"sourceCode":"      }\n\n      setError(null);\n      setDownloadProgress({ completed: 0, total: files.length, failed: [] });\n\n      try {\n        let accessToken = token?.access_token;\n        if (!accessToken) {\n          showToast({\n            message: 'Getting SharePoint access token...',\n            status: 'info',\n            duration: 2000,\n          });\n\n          const tokenResult = await refetchToken();\n          accessToken = tokenResult.data?.access_token;\n\n          if (!accessToken) {\n            throw new Error('Failed to obtain SharePoint access token');\n          }\n        }\n\n        showToast({\n          message: `Downloading ${files.length} file(s) from SharePoint...`,\n          status: 'info',\n          duration: 3000,\n        });\n\n        const downloadedFiles = await batchDownloadMutation.mutateAsync({\n          files,\n          accessToken,\n          onProgress: (progress) => {\n            setDownloadProgress(progress);\n\n            if (files.length > 5 && progress.completed % 3 === 0) {\n              showToast({\n                message: `Downloaded ${progress.completed}/${progress.total} files...`,","sourceCodeStart":38,"sourceCodeEnd":74,"githubUrl":"https://github.com/danny-avila/LibreChat/blob/5ff282f9006c436e561de1afd39a481bea1ef0d8/client/src/hooks/Files/useSharePointDownload.ts#L38-L74","documentation":"Thrown when, after explicitly refetching the Graph token via `useSharePointToken`, the result still has no `access_token`. The token originates server-side: the client calls `/api/auth/graph-token?scopes=...` (requireJwtAuth), which reads `req.user.federatedTokens.access_token` and performs on-behalf-of exchange via `getGraphApiToken`. A missing token means either the backend rejected the request (400 missing scopes, 401 no federated token, 500 exchange failure) or the current user is not an Entra/OpenID user with federated credentials.","triggerScenarios":"The user is logged in via a non-OpenID provider (local/google) and has no `federatedTokens` to exchange; the backend's `getGraphApiToken` OBO call failed (Microsoft Graph/AADSTS error); `scopes` query param empty (400); the `sharePointPickerGraphScope` startup config is unset so the requested scope is invalid; user's refresh token expired and silent OBO failed.","commonSituations":"Enabling the SharePoint file picker for users who authenticated via local/email login (no federated token); AAD app registration missing the Graph API permissions/admin consent for the OBO scope; `SHAREPOINT_PICKER_GRAPH_SCOPE` / `SHAREPOINT_PICKER_SHAREPOINT_SCOPE` env unset or malformed; transient AADSTS errors during token exchange.","solutions":["Confirm the user authenticated via OpenID/Entra (`user.provider === 'openid'`) — local/google users cannot get a Graph token through OBO.","Check the server logs around `/api/auth/graph-token` for the specific 4xx/5xx and AADSTS error from `getGraphApiToken`.","Verify the AAD app registration has the required Graph delegated permissions with admin consent, and that `SHAREPOINT_PICKER_GRAPH_SCOPE` is set to a valid scope string (e.g. `Files.Read.All`).","If the user's federated refresh token expired, have them re-authenticate with the IdP to refresh `federatedTokens`."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// Confirm prerequisites before attempting a SharePoint download\nif (user?.provider !== 'openid') throw new Error('SharePoint download requires an Entra/OpenID session');\nif (!startupConfig?.sharePointPickerGraphScope) throw new Error('SHAREPOINT_PICKER_GRAPH_SCOPE is not configured');","typeGuard":"function hasGraphToken(v: unknown): v is { access_token: string } {\n  return typeof v === 'object' && v !== null && typeof (v as any).access_token === 'string' && (v as any).access_token.length > 0;\n}","tryCatchPattern":"let accessToken = token?.access_token;\nif (!accessToken) {\n  const result = await refetchToken();\n  accessToken = result.data?.access_token;\n}\nif (!accessToken) throw new Error('Failed to obtain SharePoint access token');","preventionTips":["Restrict the SharePoint UI to OpenID/Entra users (provider === 'openid').","Confirm the AAD app registration has Graph delegated permissions with admin consent and the configured scope is valid.","Monitor /api/auth/graph-token 4xx/5xx to catch OBO exchange failures early."],"tags":["sharepoint","microsoft-graph","oauth","token","azure-ad","config"],"backgroundTag":null,"analyzedSha":"5ff282f9006c436e561de1afd39a481bea1ef0d8","analyzedAt":"2026-08-12T21:38:08.145Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}