Skip to main content
RapidDev - Software Development Agency
bolt-ai-integrationsBolt Chat + API Route

How to Integrate Bolt.new with OneDrive

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.

What you'll learn

  • How to register an Azure AD application and configure OAuth 2.0 permissions for OneDrive access
  • How to implement the Microsoft OAuth authorization code flow in Next.js API routes
  • How to use the Microsoft Graph client to list, upload, download, and share OneDrive files
  • How to build a file browser React component that displays OneDrive folder contents
  • Why OAuth callback flows require a deployed URL and how to test after deploying to Netlify
Book a free consultation
4.9Clutch rating
600+Happy partners
17+Countries served
190+Team members
Intermediate17 min read45 minutesStorageApril 2026RapidDev Engineering Team
TL;DR

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

Bolt Chat + API Route

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

1

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.

Bolt.new Prompt

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

.env
1# .env
2MICROSOFT_CLIENT_ID=your_azure_ad_application_client_id
3MICROSOFT_CLIENT_SECRET=your_azure_ad_client_secret_value
4MICROSOFT_REDIRECT_URI=https://your-app.netlify.app/api/auth/microsoft/callback
5MICROSOFT_TENANT_ID=common
6
7# After deployment, add to Netlify Dashboard:
8# Site Settings Environment Variables add all four above

Pro 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.

2

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.

Bolt.new Prompt

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

app/api/auth/microsoft/route.ts
1// app/api/auth/microsoft/route.ts
2import { NextResponse } from 'next/server';
3import crypto from 'crypto';
4
5export 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}
19
20// app/api/auth/microsoft/callback/route.ts
21import { NextRequest, NextResponse } from 'next/server';
22
23export 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;
28
29 if (!code || state !== storedState) {
30 return NextResponse.redirect('/login?error=invalid_state');
31 }
32
33 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();
48
49 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.

3

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.

Bolt.new Prompt

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

lib/graph.ts
1// lib/graph.ts
2import { Client } from '@microsoft/microsoft-graph-client';
3import 'isomorphic-fetch';
4
5export function getGraphClient(accessToken: string): Client {
6 return Client.init({
7 authProvider: (done) => done(null, accessToken),
8 });
9}
10
11export interface DriveItem {
12 id: string;
13 name: string;
14 size?: number;
15 lastModifiedDateTime: string;
16 isFolder: boolean;
17 downloadUrl?: string;
18 mimeType?: string;
19}
20
21// app/api/onedrive/files/route.ts
22import { NextRequest, NextResponse } from 'next/server';
23import { getGraphClient, DriveItem } from '@/lib/graph';
24
25export 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 }
30
31 const { searchParams } = new URL(request.url);
32 const folderId = searchParams.get('folderId');
33 const client = getGraphClient(accessToken);
34
35 try {
36 const endpoint = folderId
37 ? `/me/drive/items/${folderId}/children`
38 : '/me/drive/root/children';
39
40 const result = await client
41 .api(endpoint)
42 .select('id,name,size,lastModifiedDateTime,file,folder,@microsoft.graph.downloadUrl')
43 .orderby('name')
44 .get();
45
46 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 }));
55
56 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.

4

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.

Bolt.new Prompt

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

components/OneDriveBrowser.tsx
1// Utility functions for the file browser:
2
3function 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}
9
10function 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}
17
18function 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.

5

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.

Bolt.new Prompt

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

netlify.toml
1# netlify.toml
2[build]
3 command = "npm run build"
4 publish = ".next"
5
6[build.environment]
7 NODE_VERSION = "20"
8
9[[plugins]]
10 package = "@netlify/plugin-nextjs"
11
12# Required environment variables in Netlify Dashboard:
13# MICROSOFT_CLIENT_ID
14# MICROSOFT_CLIENT_SECRET
15# MICROSOFT_REDIRECT_URI = https://your-app.netlify.app/api/auth/microsoft/callback
16# MICROSOFT_TENANT_ID = common

Pro 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.

Bolt.new Prompt

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.

Bolt.new Prompt

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.

Bolt.new Prompt

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.

typescript
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.

typescript
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

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.

RapidDev

Talk to an Expert

Our team has built 600+ apps. Get personalized help with your project.

Book a free consultation

Need help with your project?

Our experts have built 600+ apps and can accelerate your development. Book a free consultation — no strings attached.

Book a free consultation

We put the rapid in RapidDev

Need a dedicated strategic tech and growth partner? Discover what RapidDev can do for your business! Book a call with our team to schedule a free, no-obligation consultation. We'll discuss your project and provide a custom quote at no cost.