OneDrive integrates with Bolt.new via the Microsoft Graph API — an HTTP REST API that works in Bolt's WebContainer. Register an Azure AD app to get OAuth credentials, implement the OAuth 2.0 authorization code flow in a Next.js API route, then use the @microsoft/microsoft-graph-client SDK to upload, download, list, and share files. OAuth redirect URIs require a deployed URL, not the Bolt preview, so deploy to Netlify for testing the authentication flow.
OneDrive in Bolt.new: Microsoft Graph API for Cloud File Management
OneDrive is the native cloud storage for Microsoft 365 — Word documents, Excel spreadsheets, PowerPoint presentations, and files synced from Windows all live in OneDrive. For organizations using Microsoft 365, integrating OneDrive into a Bolt.new app means giving users access to their existing work files without forcing them to re-upload anything. This is particularly valuable for enterprise tools, document management systems, and productivity apps that need to work with the Microsoft ecosystem.
Microsoft Graph is the single API endpoint for all Microsoft 365 services: OneDrive files, Outlook email, Teams messages, SharePoint documents, and calendar events all go through graph.microsoft.com. The Graph API is HTTP-based (REST + JSON), making it fully compatible with Bolt's WebContainer. The @microsoft/microsoft-graph-client package communicates over HTTPS and installs as a pure JavaScript package — no native binaries, no TCP connections required.
The main integration challenge is OAuth 2.0 authentication. Microsoft uses the authorization code flow: your app redirects the user to Microsoft's login page, Microsoft redirects back to a callback URL with an authorization code, your server exchanges the code for an access token. The callback URL must be pre-registered in Azure AD and must be a stable, publicly accessible URL. Bolt's WebContainer URLs (which look like hash.local.webcontainer-api.io) are not stable and cannot be registered. You need to deploy to Netlify or Bolt Cloud and register the deployed URL as the OAuth redirect URI before the authentication flow works end-to-end.
Integration method
OneDrive integration uses the Microsoft Graph API over HTTPS, which works in Bolt's WebContainer. You register an Azure AD application to get OAuth 2.0 credentials, implement the authorization code flow in Next.js API routes to obtain user access tokens, and use the @microsoft/microsoft-graph-client to perform file operations. The OAuth redirect URI must be registered with a deployed URL — OAuth callback flows do not work in the Bolt preview since WebContainer URLs are not stable redirect URIs.
Prerequisites
- Microsoft Azure account (free at portal.azure.com) for registering an Azure AD application
- A Bolt.new Next.js project for the API routes and OAuth callback handling
- OneDrive account for testing (Microsoft personal account or Microsoft 365 work/school account)
- A deployed URL on Netlify or Bolt Cloud to use as the OAuth redirect URI — OAuth callback does not work in the Bolt preview
- Basic familiarity with OAuth 2.0 concepts: authorization code, access token, refresh token, scopes
Step-by-step guide
Register an Azure AD Application
Register an Azure AD Application
The first step for any Microsoft Graph integration is registering an Azure AD application. This gives your Bolt app a client ID and client secret that Microsoft uses to identify your application during the OAuth flow. Log into portal.azure.com and navigate to Azure Active Directory → App registrations → New registration. Fill in the registration form: Name (your app name, e.g., 'MyBoltApp'), Supported account types (choose 'Accounts in any organizational directory and personal Microsoft accounts' for the broadest compatibility — this allows both work and personal OneDrive), Redirect URI (set to 'Web' type and enter your Netlify URL + /api/auth/microsoft/callback, e.g., https://your-app.netlify.app/api/auth/microsoft/callback). After registering, you land on the app's Overview page showing your Application (client) ID — copy this. Then navigate to Certificates & secrets → New client secret, enter a description, set expiry to 24 months, and click Add. Copy the secret Value immediately — it is only shown once. Next, configure API permissions: go to API permissions → Add a permission → Microsoft Graph → Delegated permissions. Add these scopes: Files.ReadWrite (create, read, update, delete user's files), offline_access (enables refresh tokens), and optionally User.Read (to get the user's name and email). Click 'Grant admin consent' if you are testing with a work account — personal accounts grant consent during the OAuth flow automatically.
Create a .env file with these Microsoft OAuth environment variables (I'll fill in the values): MICROSOFT_CLIENT_ID=your_azure_ad_app_client_id, MICROSOFT_CLIENT_SECRET=your_azure_ad_app_client_secret, MICROSOFT_REDIRECT_URI=https://your-app.netlify.app/api/auth/microsoft/callback, MICROSOFT_TENANT_ID=common (use 'common' for multi-tenant apps supporting both personal and work accounts)
Paste this in Bolt.new chat
1# .env2MICROSOFT_CLIENT_ID=your_azure_ad_application_client_id3MICROSOFT_CLIENT_SECRET=your_azure_ad_client_secret_value4MICROSOFT_REDIRECT_URI=https://your-app.netlify.app/api/auth/microsoft/callback5MICROSOFT_TENANT_ID=common67# After deployment, add to Netlify Dashboard:8# Site Settings → Environment Variables → add all four abovePro tip: For local development testing, add both a production redirect URI (your Netlify domain) and a local redirect URI (http://localhost:3000/api/auth/microsoft/callback) in Azure AD app registration. Azure AD allows multiple redirect URIs per app.
Expected result: Azure AD app is registered with client ID and client secret. API permissions include Files.ReadWrite and offline_access. Redirect URI matches your Netlify URL. .env file has all four Microsoft OAuth variables.
Implement Microsoft OAuth API Routes
Implement Microsoft OAuth API Routes
The OAuth authorization code flow requires two API routes: an initiation route that redirects users to Microsoft's login page, and a callback route that exchanges the authorization code for access tokens. Microsoft's identity platform is OpenID Connect compatible, meaning the same flow works for both login and permission consent. The initiation route (/api/auth/microsoft) builds the authorization URL using your MICROSOFT_CLIENT_ID, MICROSOFT_REDIRECT_URI, and the scopes you need (Files.ReadWrite offline_access User.Read openid). It adds a state parameter — a random value you generate and store in a session cookie — to prevent CSRF attacks. The user is redirected to this URL and sees Microsoft's login screen. The callback route (/api/auth/microsoft/callback) receives the authorization code from Microsoft after the user consents. It validates the state parameter against what you stored (CSRF protection), then makes a POST request to https://login.microsoftonline.com/{tenant}/oauth2/v2.0/token to exchange the code for an access_token, refresh_token, and id_token. Store the tokens securely — access tokens expire in 1 hour, but you can use the refresh token to obtain new ones. For a simple Bolt app, store tokens in an httpOnly cookie or a server-side session. Never store them in localStorage (XSS risk) or client-side state. This OAuth flow only works on a deployed app since the redirect URI must match the registered URL exactly. During Bolt development, you can test the file operation API routes independently using a test access token obtained manually from Microsoft Graph Explorer (graph.microsoft.com) — paste a test token into the API route for development iteration before wiring up the full OAuth flow.
Create Microsoft OAuth 2.0 routes in Next.js. Route 1: GET /api/auth/microsoft — redirects to Microsoft's authorization URL with client_id, redirect_uri, response_type: code, scope: 'Files.ReadWrite offline_access User.Read openid', and a random state parameter stored in a signed session cookie. Route 2: GET /api/auth/microsoft/callback — validates state cookie, exchanges code for tokens via POST to https://login.microsoftonline.com/common/oauth2/v2.0/token, stores access_token and refresh_token in httpOnly session cookies, redirects to /dashboard. Use MICROSOFT_CLIENT_ID, MICROSOFT_CLIENT_SECRET, MICROSOFT_REDIRECT_URI from environment variables. Add a GET /api/auth/microsoft/logout route that clears the token cookies.
Paste this in Bolt.new chat
1// app/api/auth/microsoft/route.ts2import { NextResponse } from 'next/server';3import crypto from 'crypto';45export async function GET() {6 const state = crypto.randomBytes(16).toString('hex');7 const params = new URLSearchParams({8 client_id: process.env.MICROSOFT_CLIENT_ID!,9 response_type: 'code',10 redirect_uri: process.env.MICROSOFT_REDIRECT_URI!,11 scope: 'Files.ReadWrite offline_access User.Read openid',12 state,13 });14 const authUrl = `https://login.microsoftonline.com/common/oauth2/v2.0/authorize?${params}`;15 const response = NextResponse.redirect(authUrl);16 response.cookies.set('oauth_state', state, { httpOnly: true, secure: true, maxAge: 600 });17 return response;18}1920// app/api/auth/microsoft/callback/route.ts21import { NextRequest, NextResponse } from 'next/server';2223export async function GET(request: NextRequest) {24 const { searchParams } = new URL(request.url);25 const code = searchParams.get('code');26 const state = searchParams.get('state');27 const storedState = request.cookies.get('oauth_state')?.value;2829 if (!code || state !== storedState) {30 return NextResponse.redirect('/login?error=invalid_state');31 }3233 const tokenRes = await fetch(34 `https://login.microsoftonline.com/common/oauth2/v2.0/token`,35 {36 method: 'POST',37 headers: { 'Content-Type': 'application/x-www-form-urlencoded' },38 body: new URLSearchParams({39 client_id: process.env.MICROSOFT_CLIENT_ID!,40 client_secret: process.env.MICROSOFT_CLIENT_SECRET!,41 code,42 redirect_uri: process.env.MICROSOFT_REDIRECT_URI!,43 grant_type: 'authorization_code',44 }),45 }46 );47 const tokens = await tokenRes.json();4849 const response = NextResponse.redirect('/dashboard');50 response.cookies.set('ms_access_token', tokens.access_token, { httpOnly: true, secure: true, maxAge: 3600 });51 response.cookies.set('ms_refresh_token', tokens.refresh_token, { httpOnly: true, secure: true, maxAge: 86400 * 30 });52 response.cookies.delete('oauth_state');53 return response;54}Pro tip: Microsoft access tokens expire after 1 hour. Add a token refresh helper that checks token expiry before Graph API calls and uses the refresh token to get a new access token automatically, preventing users from having to re-authorize after an hour.
Expected result: Navigating to /api/auth/microsoft redirects to Microsoft's login. After authorization, the callback route stores tokens in httpOnly cookies. This flow only works on the deployed Netlify app, not in the Bolt preview.
Build OneDrive File Operations with Microsoft Graph Client
Build OneDrive File Operations with Microsoft Graph Client
With OAuth tokens in place, use the @microsoft/microsoft-graph-client package to interact with OneDrive. The Graph client handles authentication header injection, request retries, and response parsing. Initialize it with the user's access token from your session cookies. Key Microsoft Graph endpoints for OneDrive: GET /me/drive/root/children (root folder contents), GET /me/drive/items/{itemId}/children (subfolder contents), GET /me/drive/items/{itemId}/content (download file content), PUT /me/drive/root:/{path}:/content (upload a file by path), POST /me/drive/items/{itemId}/createLink (generate a sharing link). The Graph API returns DriveItem objects — each has properties: id, name, size, lastModifiedDateTime, file (if file) or folder (if folder), @microsoft.graph.downloadUrl (temporary download URL). For file listing, the response includes an array of DriveItem objects. Files have a 'file' property with mimeType; folders have a 'folder' property with childCount. Use this to determine the icon to display in your file browser. For large folders, use Graph's pagination: the response may include @odata.nextLink — follow this URL to get the next page of results. File upload uses a simple PUT request for files under 4MB, or the resumable upload session API for larger files. For user uploads in a Bolt app, files up to 4MB work fine with the simple PUT; guide users to use smaller files or implement the resumable session for production apps handling large documents.
Install @microsoft/microsoft-graph-client. Create lib/graph.ts that exports a function getGraphClient(accessToken: string) that returns a configured Client instance. Create API routes: GET /api/onedrive/files?folderId={id} (lists folder contents, defaults to root), GET /api/onedrive/files/[id]/download-url (returns a download URL for the file), POST /api/onedrive/upload (accepts filename and base64 file content, uploads to 'AppUploads' folder in OneDrive). Each route reads the ms_access_token from the request cookies. Return {items: DriveItem[]} for the list route, {downloadUrl: string} for download, {fileId: string, fileName: string} for upload. Create TypeScript interface DriveItem with: id, name, size (number, optional for folders), lastModifiedDateTime, isFolder (boolean derived from whether folder property exists).
Paste this in Bolt.new chat
1// lib/graph.ts2import { Client } from '@microsoft/microsoft-graph-client';3import 'isomorphic-fetch';45export function getGraphClient(accessToken: string): Client {6 return Client.init({7 authProvider: (done) => done(null, accessToken),8 });9}1011export interface DriveItem {12 id: string;13 name: string;14 size?: number;15 lastModifiedDateTime: string;16 isFolder: boolean;17 downloadUrl?: string;18 mimeType?: string;19}2021// app/api/onedrive/files/route.ts22import { NextRequest, NextResponse } from 'next/server';23import { getGraphClient, DriveItem } from '@/lib/graph';2425export async function GET(request: NextRequest) {26 const accessToken = request.cookies.get('ms_access_token')?.value;27 if (!accessToken) {28 return NextResponse.json({ error: 'Not authenticated' }, { status: 401 });29 }3031 const { searchParams } = new URL(request.url);32 const folderId = searchParams.get('folderId');33 const client = getGraphClient(accessToken);3435 try {36 const endpoint = folderId37 ? `/me/drive/items/${folderId}/children`38 : '/me/drive/root/children';3940 const result = await client41 .api(endpoint)42 .select('id,name,size,lastModifiedDateTime,file,folder,@microsoft.graph.downloadUrl')43 .orderby('name')44 .get();4546 const items: DriveItem[] = result.value.map((item: Record<string, unknown>) => ({47 id: item.id as string,48 name: item.name as string,49 size: item.size as number | undefined,50 lastModifiedDateTime: item.lastModifiedDateTime as string,51 isFolder: Boolean(item.folder),52 downloadUrl: item['@microsoft.graph.downloadUrl'] as string | undefined,53 mimeType: item.file ? (item.file as { mimeType: string }).mimeType : undefined,54 }));5556 return NextResponse.json({ items });57 } catch (error: unknown) {58 const e = error as { message: string };59 return NextResponse.json({ error: e.message }, { status: 500 });60 }61}Pro tip: The @microsoft.graph.downloadUrl in the list response is a pre-authenticated temporary download link valid for a few hours. Use it for direct browser downloads without an additional API call. However, store the driveItem id (not this URL) in your database since the URL expires.
Expected result: GET /api/onedrive/files returns a list of DriveItems from the user's OneDrive root or specified folder. The Graph client successfully reads files using the stored access token.
Build the File Browser React Component
Build the File Browser React Component
With the API routes returning OneDrive file data, build the React UI for browsing and selecting files. The file browser needs to handle folder navigation, display file metadata, and allow users to select or download files. A breadcrumb trail shows the current path and allows navigating back to parent folders. State management for the file browser: track the current folderId (null for root), the folder navigation history as a stack (for back navigation and breadcrumb), the list of DriveItems in the current folder, loading state, and error state. When the user clicks a folder, push the current folder to the history stack and set the new folderId. Back button pops from the history stack. For file icons, map MIME types to icons: image/* → image icon, application/pdf → PDF icon, application/vnd.openxmlformats-officedocument.* (Office formats) → Word/Excel/PowerPoint icons, folders use a folder icon. Use text-based emoji or an icon library like Lucide React (which Bolt uses by default) for the icons. File size formatting helper: OneDrive returns size in bytes — convert to KB/MB for display. File date formatting: lastModifiedDateTime is ISO 8601 — format using JavaScript's Intl.DateTimeFormat for locale-appropriate display.
Build a OneDriveBrowser React component. State: currentFolderId (string | null, starts null for root), history (array of {folderId, folderName} for breadcrumbs), items (DriveItem[]), loading, error. On mount and folderId change, fetch from /api/onedrive/files?folderId={id}. Layout: header with breadcrumb trail (Home > Folder1 > Folder2, each clickable), file list with columns: icon (folder or file emoji based on isFolder and mimeType), name (clickable — folders navigate in, files trigger onFileSelect prop), lastModifiedDateTime (formatted as 'Jan 15, 2026'), size (formatted as KB/MB, '-' for folders). Empty state message 'This folder is empty' when no items. Loading spinner during fetch. Error message on failure. Styling: clean table layout, hover highlight on rows, cursor-pointer on clickable rows.
Paste this in Bolt.new chat
1// Utility functions for the file browser:23function formatFileSize(bytes?: number): string {4 if (!bytes) return '-';5 if (bytes < 1024) return `${bytes} B`;6 if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;7 return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;8}910function formatDate(isoDate: string): string {11 return new Intl.DateTimeFormat('en-US', {12 year: 'numeric',13 month: 'short',14 day: 'numeric',15 }).format(new Date(isoDate));16}1718function getFileIcon(item: { isFolder: boolean; mimeType?: string }): string {19 if (item.isFolder) return '📁';20 const mime = item.mimeType || '';21 if (mime.startsWith('image/')) return '🖼️';22 if (mime === 'application/pdf') return '📄';23 if (mime.includes('word')) return '📝';24 if (mime.includes('spreadsheet') || mime.includes('excel')) return '📊';25 if (mime.includes('presentation') || mime.includes('powerpoint')) return '📑';26 return '📎';27}Pro tip: Add a search bar that calls GET /me/drive/root/search(q='{query}') via the Graph API to search across all OneDrive files, not just the current folder. This significantly improves usability for users with many files.
Expected result: The OneDriveBrowser component renders a navigable file browser showing OneDrive folder contents with icons, names, dates, and sizes. Clicking folders navigates into them with breadcrumb navigation.
Deploy to Netlify and Test OAuth Flow End-to-End
Deploy to Netlify and Test OAuth Flow End-to-End
Deploy to Netlify so the Microsoft OAuth redirect URI works correctly. The OAuth flow is the only part that cannot be tested in Bolt's WebContainer — file operations (listing, uploading, downloading via Graph API) are outbound HTTPS requests that work in the preview if you have a test access token, but the OAuth initiation → callback flow requires a stable deployed URL. Deploy steps: connect your Bolt project to Netlify via Settings → Applications → Netlify, publish the project. After deployment, note your Netlify URL (e.g., your-app.netlify.app). In Azure AD app registration, verify your Redirect URI matches https://your-app.netlify.app/api/auth/microsoft/callback exactly (including https, no trailing slash). Add your B2 environment variables in Netlify Dashboard → Site Settings → Environment Variables: MICROSOFT_CLIENT_ID, MICROSOFT_CLIENT_SECRET, MICROSOFT_REDIRECT_URI (your Netlify callback URL), MICROSOFT_TENANT_ID. Test the full flow: navigate to your Netlify app, click a 'Connect OneDrive' button that triggers /api/auth/microsoft, complete the Microsoft login, confirm you land back on /dashboard with OneDrive files accessible. Check Netlify function logs if the callback fails — common issues are a mismatched redirect URI or missing client secret. Once authenticated, the file operations continue working on subsequent visits using the refresh token to obtain new access tokens.
Create a netlify.toml configuration for deployment, a ConnectOneDrive button component that links to /api/auth/microsoft when clicked, and a useOneDriveAuth hook that checks if ms_access_token cookie exists and returns {isConnected: boolean, connectUrl: '/api/auth/microsoft', disconnectUrl: '/api/auth/microsoft/logout'}. Show the ConnectOneDrive button if !isConnected, and the OneDriveBrowser component if isConnected.
Paste this in Bolt.new chat
1# netlify.toml2[build]3 command = "npm run build"4 publish = ".next"56[build.environment]7 NODE_VERSION = "20"89[[plugins]]10 package = "@netlify/plugin-nextjs"1112# Required environment variables in Netlify Dashboard:13# MICROSOFT_CLIENT_ID14# MICROSOFT_CLIENT_SECRET15# MICROSOFT_REDIRECT_URI = https://your-app.netlify.app/api/auth/microsoft/callback16# MICROSOFT_TENANT_ID = commonPro tip: Microsoft access tokens are only valid for 1 hour. Add a middleware check that runs before file operation API routes: if the access token is missing or expired, return a 401 response that your React code handles by showing the 'Connect OneDrive' button again.
Expected result: Deployed app on Netlify allows users to authenticate with Microsoft, redirects back to the app, and shows their OneDrive files in the browser. OAuth flow works end-to-end with the deployed URL.
Common use cases
File Browser Widget for Document Management Apps
Build an in-app OneDrive file browser that lets users navigate their OneDrive folders, preview documents, and select files to import into your application. Users authenticate once with Microsoft OAuth, and the access token grants your app permission to list and read files from their OneDrive.
Build a OneDrive file browser component using Microsoft Graph API. Create two API routes: GET /api/onedrive/files?folderId={id} (lists folder contents, defaults to root) and GET /api/onedrive/files/[id]/download-url (generates a download URL for a file). Both routes read the user's OneDrive access token from the session. Create a OneDriveBrowser React component that shows a two-panel layout: left panel shows folder tree navigation, right panel shows file list with filename, last modified date, file size, and file type icon. Clicking a folder navigates into it. Clicking a file triggers onFileSelect(fileId, fileName, downloadUrl) prop callback. Include a back-navigation breadcrumb trail.
Copy this prompt to try it in Bolt.new
Document Upload and Sharing from Your App
Allow users to save documents generated by your app directly to their OneDrive, organized into app-specific folders. After saving, generate a shareable link via Microsoft Graph that users can share with colleagues. This is useful for report generators, invoice creators, or any app that produces documents users need to distribute.
Add OneDrive save and share functionality to my report generator. Create a POST /api/onedrive/save route that accepts a filename and file content (base64 or text), uploads it to a 'MyApp Reports' folder in the user's OneDrive (creating the folder if it doesn't exist), and returns the saved file's driveItem ID. Create a POST /api/onedrive/share route that accepts a driveItem ID and returns a shareable view-only link using createLink action. Add a SaveToOneDrive button component that calls these routes and shows the shareable link in a copy-to-clipboard dialog after saving.
Copy this prompt to try it in Bolt.new
OneDrive Sync for Project File Management
Integrate OneDrive as a file storage backend where users can attach OneDrive files to app records (tasks, projects, customers). Store the file's driveItem ID and name in your database. When users need to access the file, fetch a fresh download URL on demand. This avoids copying files into your own storage while still enabling in-app file access.
Build an OneDrive file attachment system for my project management app. Users can attach existing OneDrive files to any project card. Create a GET /api/onedrive/files route for browsing and a POST /api/projects/[id]/attachments route that accepts {driveItemId: string, fileName: string} and stores it in a Supabase attachments table (id, project_id, drive_item_id, file_name, attached_by, attached_at). Create a GET /api/onedrive/files/[driveItemId]/url route that generates a short-lived download URL for a stored file. Show attachments on the project card with filename and a download button.
Copy this prompt to try it in Bolt.new
Troubleshooting
Microsoft OAuth redirect sends user back to an error page: 'The redirect URI specified in the request does not match the redirect URIs configured for the application'
Cause: The MICROSOFT_REDIRECT_URI environment variable in your app does not exactly match the redirect URI registered in Azure AD app registration. Even a minor difference (trailing slash, http vs https, different port) causes this error.
Solution: Go to Azure AD app registration → Authentication → Redirect URIs and verify the URI matches exactly. Update both the Azure AD registration and the MICROSOFT_REDIRECT_URI environment variable in Netlify to the same exact string: https://your-app.netlify.app/api/auth/microsoft/callback
Microsoft Graph API returns 401 Unauthorized even with a valid-looking access token
Cause: The access token has expired (Microsoft tokens expire after 1 hour), the token was issued without the required scopes (Files.ReadWrite), or the token is from a different tenant than expected.
Solution: Check token expiry: decode the access token at jwt.ms to see the exp (expiration) claim and scp (scopes) claim. If expired, use the refresh token to get a new access token. If scopes are missing, the user needs to re-authorize after you add the required scopes in Azure AD app registration.
1// Token refresh helper:2async function refreshAccessToken(refreshToken: string): Promise<string> {3 const res = await fetch('https://login.microsoftonline.com/common/oauth2/v2.0/token', {4 method: 'POST',5 headers: { 'Content-Type': 'application/x-www-form-urlencoded' },6 body: new URLSearchParams({7 client_id: process.env.MICROSOFT_CLIENT_ID!,8 client_secret: process.env.MICROSOFT_CLIENT_SECRET!,9 grant_type: 'refresh_token',10 refresh_token: refreshToken,11 scope: 'Files.ReadWrite offline_access',12 }),13 });14 const data = await res.json();15 return data.access_token;16}OneDrive file list returns 403 Forbidden: 'Access denied. You do not have permission to access this item.'
Cause: The authenticated user doesn't have permission to access the requested folder or file — may be a shared folder from another user they don't have access to, or the folderId belongs to a different drive.
Solution: Verify the folderId is from the user's own OneDrive drive (/me/drive/...) not a shared or team drive. For shared drives, use the Drives API endpoint instead: /drives/{driveId}/items/{itemId}/children. Handle 403 errors gracefully by showing a permission error message.
@microsoft/microsoft-graph-client throws 'Cannot find module isomorphic-fetch' in Next.js
Cause: The Graph client requires a global fetch polyfill in some environments. Next.js 14+ has native fetch, but the client import may still expect the isomorphic-fetch module.
Solution: Install isomorphic-fetch: prompt Bolt 'Install isomorphic-fetch and import it at the top of lib/graph.ts before the Client import.' Alternatively, use the fetch middleware configuration in the Graph client initialization.
1// In lib/graph.ts, add at the very top:2import 'isomorphic-fetch';3import { Client } from '@microsoft/microsoft-graph-client';4// OR install and use the fetch middleware:5// import { FetchOptions } from '@microsoft/microsoft-graph-client';Best practices
- Store Microsoft OAuth tokens in httpOnly cookies, never in localStorage or client-side React state — access tokens are bearer credentials that grant OneDrive access
- Always implement token refresh logic using the refresh_token — Microsoft access tokens expire after 1 hour and users should not need to re-authorize every session
- Request only the minimum OAuth scopes your app needs — Files.Read instead of Files.ReadWrite if you only need to browse files, never request Mail.ReadWrite or Calendar permissions unless required
- Handle the OAuth redirect URI mismatch error gracefully with a clear user-facing message pointing to re-authorization, not a blank 500 error page
- Test the Microsoft OAuth flow on your deployed Netlify app — the WebContainer preview URL is not a valid OAuth redirect URI and the flow will always fail there
- Use the @microsoft.graph.downloadUrl from list responses for direct file downloads instead of a separate API call — it is a pre-authenticated temporary URL valid for a few hours
- For large OneDrive directories, implement pagination using @odata.nextLink to avoid loading all files at once — users' OneDrive folders may contain thousands of files
Alternatives
Dropbox is platform-agnostic with a simpler OAuth setup and no Azure AD registration required; OneDrive is better for organizations where users already have Microsoft 365 accounts and existing work files.
Box offers enterprise file management with HIPAA and FedRAMP compliance and granular permission management; OneDrive is more accessible for Microsoft 365 organizations without specialized compliance requirements.
AWS S3 is raw cloud storage you fully control with simpler programmatic access; OneDrive is a user-facing storage service requiring OAuth — choose S3 for app-managed storage, OneDrive for accessing users' existing Microsoft files.
Google Drive uses the same OAuth 2.0 pattern as OneDrive but integrates with Google Workspace; OneDrive integrates with Microsoft 365 — choose based on your users' existing cloud ecosystem.
Frequently asked questions
Does the OneDrive integration work in Bolt's WebContainer preview?
File operations (listing, uploading, downloading via Microsoft Graph) work in the Bolt preview because they are outbound HTTPS requests. However, the OAuth authentication flow requires a stable redirect URI — Bolt's WebContainer URL is not stable and cannot be registered in Azure AD. Test OAuth authentication on your deployed Netlify app. Once you have a valid access token, you can test individual file operations in the preview using a test token from Microsoft Graph Explorer.
Can I use personal Microsoft accounts (Outlook.com, Hotmail) or only work accounts?
Both work. When registering your Azure AD app, choose 'Accounts in any organizational directory and personal Microsoft accounts' as the supported account type. Set MICROSOFT_TENANT_ID to 'common' in your environment variables — this allows the OAuth flow to work for both personal Microsoft accounts (outlook.com, hotmail.com, live.com) and work/school Microsoft 365 accounts.
How long do Microsoft access tokens last and what happens when they expire?
Microsoft access tokens expire after 1 hour. Refresh tokens (obtained with the offline_access scope) last for 14-90 days depending on Microsoft's policies. Implement a token refresh mechanism: before each Graph API call, check if the stored access token is close to expiry (within 5 minutes) and use the refresh token to obtain a new access token. If the refresh token has also expired, the user must re-authorize.
Is it possible to access SharePoint document libraries through this integration?
Yes — SharePoint documents are accessible through the same Microsoft Graph API. SharePoint drives use the /drives/{driveId} endpoint instead of /me/drive. You can list available SharePoint sites with GET /me/followedSites, get a site's drives with GET /sites/{siteId}/drives, then list files with GET /drives/{driveId}/root/children. The same DriveItem structure is used for both OneDrive and SharePoint files.
Can I use Microsoft Graph without implementing OAuth — for example to access my own OneDrive?
For accessing your own OneDrive in a personal project, you can get a long-lived access token from Microsoft Graph Explorer (graph.microsoft.com) and hardcode it temporarily for development. However, tokens expire after 1 hour even from Graph Explorer. For a production app, OAuth is required. For app-owned storage (not user storage), use app-only authentication with client credentials flow — but this requires an organizational Azure AD tenant, not a personal Microsoft account.
Talk to an Expert
Our team has built 600+ apps. Get personalized help with your project.
Book a free consultation