# How to Integrate Bolt.new with OneDrive

- Tool: Bolt.new
- Difficulty: Intermediate
- Time required: 45 minutes
- Last updated: April 2026

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

## Before you start

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

```
# .env
MICROSOFT_CLIENT_ID=your_azure_ad_application_client_id
MICROSOFT_CLIENT_SECRET=your_azure_ad_client_secret_value
MICROSOFT_REDIRECT_URI=https://your-app.netlify.app/api/auth/microsoft/callback
MICROSOFT_TENANT_ID=common

# After deployment, add to Netlify Dashboard:
# Site Settings → Environment Variables → add all four above
```

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

```
// app/api/auth/microsoft/route.ts
import { NextResponse } from 'next/server';
import crypto from 'crypto';

export async function GET() {
  const state = crypto.randomBytes(16).toString('hex');
  const params = new URLSearchParams({
    client_id: process.env.MICROSOFT_CLIENT_ID!,
    response_type: 'code',
    redirect_uri: process.env.MICROSOFT_REDIRECT_URI!,
    scope: 'Files.ReadWrite offline_access User.Read openid',
    state,
  });
  const authUrl = `https://login.microsoftonline.com/common/oauth2/v2.0/authorize?${params}`;
  const response = NextResponse.redirect(authUrl);
  response.cookies.set('oauth_state', state, { httpOnly: true, secure: true, maxAge: 600 });
  return response;
}

// app/api/auth/microsoft/callback/route.ts
import { NextRequest, NextResponse } from 'next/server';

export async function GET(request: NextRequest) {
  const { searchParams } = new URL(request.url);
  const code = searchParams.get('code');
  const state = searchParams.get('state');
  const storedState = request.cookies.get('oauth_state')?.value;

  if (!code || state !== storedState) {
    return NextResponse.redirect('/login?error=invalid_state');
  }

  const tokenRes = await fetch(
    `https://login.microsoftonline.com/common/oauth2/v2.0/token`,
    {
      method: 'POST',
      headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
      body: new URLSearchParams({
        client_id: process.env.MICROSOFT_CLIENT_ID!,
        client_secret: process.env.MICROSOFT_CLIENT_SECRET!,
        code,
        redirect_uri: process.env.MICROSOFT_REDIRECT_URI!,
        grant_type: 'authorization_code',
      }),
    }
  );
  const tokens = await tokenRes.json();

  const response = NextResponse.redirect('/dashboard');
  response.cookies.set('ms_access_token', tokens.access_token, { httpOnly: true, secure: true, maxAge: 3600 });
  response.cookies.set('ms_refresh_token', tokens.refresh_token, { httpOnly: true, secure: true, maxAge: 86400 * 30 });
  response.cookies.delete('oauth_state');
  return response;
}
```

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

```
// lib/graph.ts
import { Client } from '@microsoft/microsoft-graph-client';
import 'isomorphic-fetch';

export function getGraphClient(accessToken: string): Client {
  return Client.init({
    authProvider: (done) => done(null, accessToken),
  });
}

export interface DriveItem {
  id: string;
  name: string;
  size?: number;
  lastModifiedDateTime: string;
  isFolder: boolean;
  downloadUrl?: string;
  mimeType?: string;
}

// app/api/onedrive/files/route.ts
import { NextRequest, NextResponse } from 'next/server';
import { getGraphClient, DriveItem } from '@/lib/graph';

export async function GET(request: NextRequest) {
  const accessToken = request.cookies.get('ms_access_token')?.value;
  if (!accessToken) {
    return NextResponse.json({ error: 'Not authenticated' }, { status: 401 });
  }

  const { searchParams } = new URL(request.url);
  const folderId = searchParams.get('folderId');
  const client = getGraphClient(accessToken);

  try {
    const endpoint = folderId
      ? `/me/drive/items/${folderId}/children`
      : '/me/drive/root/children';

    const result = await client
      .api(endpoint)
      .select('id,name,size,lastModifiedDateTime,file,folder,@microsoft.graph.downloadUrl')
      .orderby('name')
      .get();

    const items: DriveItem[] = result.value.map((item: Record<string, unknown>) => ({
      id: item.id as string,
      name: item.name as string,
      size: item.size as number | undefined,
      lastModifiedDateTime: item.lastModifiedDateTime as string,
      isFolder: Boolean(item.folder),
      downloadUrl: item['@microsoft.graph.downloadUrl'] as string | undefined,
      mimeType: item.file ? (item.file as { mimeType: string }).mimeType : undefined,
    }));

    return NextResponse.json({ items });
  } catch (error: unknown) {
    const e = error as { message: string };
    return NextResponse.json({ error: e.message }, { status: 500 });
  }
}
```

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

```
// Utility functions for the file browser:

function formatFileSize(bytes?: number): string {
  if (!bytes) return '-';
  if (bytes < 1024) return `${bytes} B`;
  if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
  return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
}

function formatDate(isoDate: string): string {
  return new Intl.DateTimeFormat('en-US', {
    year: 'numeric',
    month: 'short',
    day: 'numeric',
  }).format(new Date(isoDate));
}

function getFileIcon(item: { isFolder: boolean; mimeType?: string }): string {
  if (item.isFolder) return '📁';
  const mime = item.mimeType || '';
  if (mime.startsWith('image/')) return '🖼️';
  if (mime === 'application/pdf') return '📄';
  if (mime.includes('word')) return '📝';
  if (mime.includes('spreadsheet') || mime.includes('excel')) return '📊';
  if (mime.includes('presentation') || mime.includes('powerpoint')) return '📑';
  return '📎';
}
```

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

```
# netlify.toml
[build]
  command = "npm run build"
  publish = ".next"

[build.environment]
  NODE_VERSION = "20"

[[plugins]]
  package = "@netlify/plugin-nextjs"

# Required environment variables in Netlify Dashboard:
# MICROSOFT_CLIENT_ID
# MICROSOFT_CLIENT_SECRET
# MICROSOFT_REDIRECT_URI = https://your-app.netlify.app/api/auth/microsoft/callback
# MICROSOFT_TENANT_ID = common
```

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

## 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

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

Prompt example:

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

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

Prompt example:

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

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

Prompt example:

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

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

```
// Token refresh helper:
async function refreshAccessToken(refreshToken: string): Promise<string> {
  const res = await fetch('https://login.microsoftonline.com/common/oauth2/v2.0/token', {
    method: 'POST',
    headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
    body: new URLSearchParams({
      client_id: process.env.MICROSOFT_CLIENT_ID!,
      client_secret: process.env.MICROSOFT_CLIENT_SECRET!,
      grant_type: 'refresh_token',
      refresh_token: refreshToken,
      scope: 'Files.ReadWrite offline_access',
    }),
  });
  const data = await res.json();
  return data.access_token;
}
```

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

```
// In lib/graph.ts, add at the very top:
import 'isomorphic-fetch';
import { Client } from '@microsoft/microsoft-graph-client';
// OR install and use the fetch middleware:
// import { FetchOptions } from '@microsoft/microsoft-graph-client';
```

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

---

Source: https://www.rapidevelopers.com/bolt-ai-integrations/onedrive
© RapidDev — https://www.rapidevelopers.com/bolt-ai-integrations/onedrive
