# OneDrive

- Tool: Bubble
- Difficulty: Advanced
- Time required: 2–3 hours
- Last updated: July 2026

## TL;DR

OneDrive is accessed through Microsoft Graph — a single API endpoint that covers OneDrive files, SharePoint libraries, Teams files, and all Microsoft 365 services. For Bubble, this means one API Connector configuration gives you access to the entire Microsoft file ecosystem. The auth challenge: Azure AD OAuth requires app registration, specific permission scopes, and explicit admin consent from a tenant Global Administrator — adding the permission to the app registration alone is not sufficient. Requires a paid Bubble plan for token refresh Backend Workflows.

## Bubble + OneDrive via Microsoft Graph: One Endpoint, the Entire Microsoft 365 File Ecosystem

OneDrive is not a standalone file service with its own dedicated API — it is part of Microsoft 365 and accessed through Microsoft Graph, a unified REST API that covers essentially all Microsoft services. The base URL is `https://graph.microsoft.com/v1.0` and a single Bearer token gives you access to OneDrive, SharePoint document libraries, Teams channels, user profiles, calendar events, mail, and more. For Bubble developers, this is valuable: if your users are on Microsoft 365, the same API Connector configuration that lets you browse OneDrive files can also access SharePoint sites and Teams shared libraries.

The authentication setup is more involved than services like Dropbox but follows a clear path. First, you register an application in the Azure portal (portal.azure.com) to get a Client ID and Client Secret. Second, you request the appropriate Microsoft Graph permissions — Files.ReadWrite.All for full OneDrive access, or Files.Read for read-only. Third, and this is the step that stops many integrators: a Global Administrator of the Azure AD tenant must grant 'admin consent' for those permissions. Adding the permission to your app registration in the Azure portal is not sufficient — admin consent is a separate, explicit approval step that a standard user account cannot complete.

For the Bubble integration, there are two auth patterns. Server-to-server (a single service account accesses files on behalf of the organization): use the client credentials OAuth flow. POST to `https://login.microsoftonline.com/{tenant-id}/oauth2/v2.0/token` with the Client ID, Client Secret, and `grant_type=client_credentials`. The response is an access token valid for approximately 60 minutes. A Backend Workflow calls this endpoint, caches the token in a Bubble Config data type, and a scheduled refresh Backend Workflow runs every 50 minutes. The API Connector uses the cached token as a Private Authorization header — no external signing proxy needed.

Per-user access (each user grants access to their own OneDrive): use the delegated OAuth 2.0 flow. The user is redirected to a Microsoft authorization URL, approves the permissions, and is redirected back with an authorization code. A Backend Workflow exchanges the code for an access token and refresh token, stored linked to the Bubble user record. Refresh tokens remain valid until revoked and can be used to get new access tokens without user re-authentication.

The Graph API supports `$select` query parameters to limit which fields are returned — critical for Bubble performance. A full file listing without `$select` can return dozens of fields per item; adding `?$select=id,name,size,lastModifiedDateTime,folder,file` returns only what you need, reducing response payload size and Bubble WU processing cost.

For file uploads, Graph's simple PUT endpoint handles files up to 4 MB: `PUT /me/drive/root:/{file-path}:/content`. Larger files require the upload session API (POST to create a session, then PUT chunks) — implementable in Bubble as multiple sequential Backend Workflow steps.

Bubble Backend Workflows are paid-plan features (Starter or above). The token refresh and upload workflows require a paid plan.

## Before you start

- A Microsoft Azure account with the ability to register Azure AD applications at portal.azure.com
- Access to the Azure AD tenant where your users' Microsoft 365 accounts live (needed to get Tenant ID)
- A Global Administrator account for the Azure AD tenant to grant admin consent for Graph permissions — a regular user or app developer cannot complete this step
- A Bubble app on a paid plan (Starter or above) — Backend Workflows required for token caching and refresh scheduling
- The Bubble API Connector plugin installed (Plugins tab → Add plugins → search 'API Connector' by Bubble)

## Step-by-step guide

### 1. Register an Azure AD app and configure Microsoft Graph permissions

Go to portal.azure.com and sign in with your Azure account. In the search bar, type 'App registrations' and select it. Click 'New registration'.

Configure the app:
- Name: 'Bubble OneDrive Integration' (or any descriptive name)
- Supported account types: 'Accounts in this organizational directory only' (for a single Microsoft 365 tenant) or 'Accounts in any organizational directory' (if building a multi-tenant app)
- Redirect URI: leave blank for now (add later when implementing delegated OAuth for per-user access)

Click 'Register'. After creation, note three values from the Overview page — you need all three:
- **Application (client) ID** — your OAuth Client ID
- **Directory (tenant) ID** — your organization's Azure AD tenant identifier
- **Object ID** — not needed for this integration

Now add Microsoft Graph permissions. Go to 'API permissions' in the left menu → 'Add a permission' → 'Microsoft Graph' → 'Application permissions' (for client credentials flow) or 'Delegated permissions' (for per-user flow). Add:
- `Files.ReadWrite.All` — read and write all files
- `Sites.Read.All` — read SharePoint sites (optional, if you need SharePoint access)
- `User.Read` — read user profile

After adding the permissions, you will see them listed with 'Status: Not granted for {tenant name}'. This status must change before any API calls work. Do NOT click 'Grant admin consent for {tenant}' here unless you are a Global Administrator — ask your organization's IT admin to do this in the next step.

Finally, create a Client Secret: go to 'Certificates & secrets' → 'New client secret'. Give it a description, set expiry (24 months is standard), and click 'Add'. Copy the secret VALUE immediately — it is shown only once.

**Expected result:** Azure AD app registered with Application ID, Directory (Tenant) ID, and Client Secret (Value, not ID) noted. Files.ReadWrite.All permission added but not yet consented.

### 2. Grant admin consent for the Microsoft Graph permissions

A Global Administrator of the Azure AD tenant must explicitly grant consent for your app to use the Files.ReadWrite.All permission. Adding the permission in the app registration is not sufficient — admin consent is a separate mandatory approval.

If you are the Global Administrator: in the Azure portal, go to Azure Active Directory → App registrations → find your app → API permissions. Click 'Grant admin consent for {your tenant name}'. A confirmation dialog appears — click 'Yes'. After a few seconds, the Status column changes from 'Not granted' to a green checkmark 'Granted for {tenant name}'.

If you are NOT the Global Administrator: contact your organization's IT department or the person who manages Azure/Microsoft 365 for your organization. They need to:
1. Log into portal.azure.com as a Global Administrator
2. Navigate to Azure Active Directory → App registrations → find your app by name or Application ID
3. Click 'API permissions' → 'Grant admin consent for {tenant}'
4. Confirm the approval

This step cannot be automated, skipped, or worked around. Until admin consent is granted, every API call returns a 403 'Insufficient privileges' error regardless of how correctly the credentials are configured. This is Microsoft's security requirement for apps accessing organizational data.

After admin consent is granted, confirm by checking the API permissions page — all requested permissions should show a green checkmark under Status.

**Expected result:** All requested Graph permissions show 'Granted for {tenant name}' with a green checkmark in the Azure portal API permissions page.

### 3. Build the token exchange Backend Workflow and API Connector

Set up Bubble to exchange Client ID and Client Secret for a Microsoft Graph access token and cache it for use across API calls.

First, add the token endpoint to the API Connector. In Bubble, go to Plugins → API Connector → Add another API. Name it 'Microsoft Graph Auth'.

Add a call named 'Get Access Token':
- Method: POST
- URL: `https://login.microsoftonline.com/{your-tenant-id}/oauth2/v2.0/token`
- Body type: Form-data
- Body fields:
  - `client_id`: your Azure AD Application Client ID (Private)
  - `client_secret`: your Azure AD Client Secret value (Private)
  - `scope`: `https://graph.microsoft.com/.default`
  - `grant_type`: `client_credentials`

Call configuration:

```json
{
  "method": "POST",
  "url": "https://login.microsoftonline.com/{tenant-id}/oauth2/v2.0/token",
  "body": {
    "client_id": "<private>",
    "client_secret": "<private>",
    "scope": "https://graph.microsoft.com/.default",
    "grant_type": "client_credentials"
  }
}
```

Set Use as: Action. Initialize call — it should return `access_token` and `expires_in`. Click Save.

Create a Bubble data type called `GraphConfig` with two fields: `access_token` (text), `expires_at` (date). Create one record manually with placeholder values.

In Backend Workflows, create `Refresh Graph Token`:
1. Action: Plugins → Microsoft Graph Auth → Get Access Token
2. Action: Data → Make changes to GraphConfig → set access_token = Step 1's access_token, expires_at = Current date/time + 3,000 seconds

Set up a recurring scheduled API Workflow to run `Refresh Graph Token` every 50 minutes (Settings → API → Schedule recurring events). Note: scheduling requires a paid Bubble plan.

Now add the main Graph API Connector. Add another API group named 'Microsoft Graph':
- Shared header: `Authorization` → `Bearer [GraphConfig's access_token from search]` → **Private** checkbox checked
- The Authorization value is dynamic — it reads the cached token from the GraphConfig data type

```
{
  "method": "POST",
  "url": "https://login.microsoftonline.com/{tenant-id}/oauth2/v2.0/token",
  "headers": {
    "Content-Type": "application/x-www-form-urlencoded"
  },
  "body": {
    "client_id": "<private>",
    "client_secret": "<private>",
    "scope": "https://graph.microsoft.com/.default",
    "grant_type": "client_credentials"
  }
}
```

**Expected result:** Microsoft Graph Auth API Connector group set up with Get Access Token call initialized and returning access_token. GraphConfig data type created. Refresh Graph Token Backend Workflow created and scheduled every 50 minutes.

### 4. Add Microsoft Graph API calls for file listing and sharing

In the 'Microsoft Graph' API Connector group, add the key calls you need for OneDrive operations.

**Call 1: List OneDrive root contents**
- Name: `List Drive Root`
- Method: GET
- URL: `https://graph.microsoft.com/v1.0/me/drive/root/children`
- Query params: `$select` = `id,name,size,lastModifiedDateTime,folder,file`
- Use as: Data
- Initialize call: run with real token. Bubble detects `value` array with file/folder objects.

Request config:
```json
{
  "method": "GET",
  "url": "https://graph.microsoft.com/v1.0/me/drive/root/children",
  "headers": {
    "Authorization": "Bearer <private>"
  },
  "params": {
    "$select": "id,name,size,lastModifiedDateTime,folder,file"
  }
}
```

For accessing a specific user's drive in a multi-user scenario, replace `/me/drive` with `/users/{userId}/drive`. For SharePoint document library access, use `/sites/{siteId}/drives` to list libraries, then `/drives/{driveId}/root/children` to list contents.

**Call 2: Create sharing link**
- Name: `Create Sharing Link`
- Method: POST
- URL: `https://graph.microsoft.com/v1.0/me/drive/items/{itemId}/createLink`
- Body type: JSON
- Body fields: `type` (text, value 'view'), `scope` (text, value 'organization')
- Use as: Action
- Initialize call with a real file ID from the listing response

**Call 3: List SharePoint sites (optional)**
- Name: `Search Sites`
- Method: GET
- URL: `https://graph.microsoft.com/v1.0/sites`
- Query params: `search` = `<dynamic>`
- Use as: Data

The `$select` parameter is critical for Bubble performance: Graph returns up to 30+ fields per file item by default. Without `$select`, a folder with 100 files returns a large payload that costs significantly more Bubble WUs to process. Always use `$select` with the minimum fields your UI needs.

```
{
  "method": "GET",
  "url": "https://graph.microsoft.com/v1.0/me/drive/root/children",
  "headers": {
    "Authorization": "Bearer <private>"
  },
  "params": {
    "$select": "id,name,size,lastModifiedDateTime,folder,file"
  }
}
```

**Expected result:** Microsoft Graph API Connector group contains initialized calls for List Drive Root (Data), Create Sharing Link (Action), and optionally Search Sites (Data). All calls return valid responses with the cached access token.

### 5. Build the Bubble file browser UI and upload workflow

Connect the Graph API calls to Bubble UI elements to create a working OneDrive file browser and upload workflow.

**File browser repeating group:**
1. Add a Repeating Group element to your page
2. Type of content: Microsoft Graph - List Drive Root (API data type)
3. Data source: Get data from external API → Microsoft Graph - List Drive Root
4. Inside cells: Text = current cell's name, Text = format as text of current cell's lastModifiedDateTime
5. Conditional formatting: if current cell has a `folder` field → show folder icon; if it has a `file` field → show file icon
6. Share button inside cells: click → Action → Create Sharing Link → set itemId = current cell's id → set App State 'share_url' = result's webUrl

**File upload workflow:**
For small files (under 4 MB), the Graph simple upload endpoint works directly:
- Add a File Uploader element and an Upload button
- On button click: Backend Workflow or client-side Action to call Graph PUT endpoint

Add a new API call to the Microsoft Graph group:
- Name: `Upload Small File`
- Method: PUT
- URL: `https://graph.microsoft.com/v1.0/me/drive/root:/{filename}:/content`
- Body type: Binary
- Use as: Action

For the file path in the URL, you can make `{filename}` dynamic by constructing the URL in the workflow action.

After a successful upload, create a OneDriveFile Bubble data type record with: `file_name` (text), `graph_item_id` (text — the id from the upload response), `uploaded_by` = Current User, `uploaded_at` = Current date/time.

**Privacy rules**: Go to Data tab → Data types → OneDriveFile → Privacy. Add a rule: Current User is uploaded_by → Allow find in searches: Yes, Allow reading all fields: Yes. Without privacy rules, any authenticated user can query OneDriveFile records.

**Token refresh check**: Before any API call, add a conditional: if GraphConfig's expires_at < Current date/time → run the Refresh Graph Token Backend Workflow → then proceed with the API call. This proactive check prevents 401 errors from expired tokens.

RapidDev's team has built Bubble apps integrating Microsoft 365 including OneDrive and SharePoint — for complex multi-user OAuth flows or SharePoint integration architecture, book a free scoping call at rapidevelopers.com/contact.

```
{
  "method": "PUT",
  "url": "https://graph.microsoft.com/v1.0/me/drive/root:/<dynamic-filename>:/content",
  "headers": {
    "Authorization": "Bearer <private>",
    "Content-Type": "<dynamic-content-type>"
  }
}
```

**Expected result:** Bubble page displays OneDrive file browser backed by Graph API, sharing link creation works for individual files, file upload sends small files to OneDrive's root folder, and OneDriveFile records are protected by Bubble privacy rules.

## Best practices

- Always grant admin consent from a Global Administrator account — adding permissions to the Azure app registration is not sufficient and every API call will fail until consent is granted. Build this into your client onboarding process for Microsoft 365 integrations.
- Use `$select` query parameters on all Graph API listing calls to return only the fields you need. A full file listing without `$select` returns up to 30+ fields per item; `?$select=id,name,size,lastModifiedDateTime,folder,file` returns only the five you display, significantly reducing Bubble WU consumption.
- Cache the Graph access token in a Bubble Config data type (single record) and refresh it every 50 minutes proactively — before the 60-minute expiry. Add an expiry check at the start of workflows that need a valid token.
- Mark the Client Secret in the API Connector's Body field as Private to prevent it from appearing in browser network requests. Never put the Client Secret in a client-side Bubble action or visible App State.
- Set Bubble privacy rules on any data type storing OneDrive file references (Graph item IDs, file names, sharing URLs). Without privacy rules, authenticated Bubble users can query each other's file metadata.
- For per-user OneDrive access (delegated OAuth), store the refresh token per Bubble User record and request new access tokens silently using the refresh token. Never store access tokens permanently — they expire and should only live in the GraphConfig cache during the ~60-minute validity window.
- For upload-heavy apps, implement the Graph upload session API for files over 4 MB rather than trying to pass large binaries through Bubble's simple PUT endpoint. Large binary handling in Bubble workflows is unreliable above a few megabytes.
- If you need access to both OneDrive files and SharePoint document libraries, you already have both through the same Microsoft Graph API Connector. Use `/sites` to enumerate SharePoint sites and `/sites/{siteId}/drives` to access their document libraries — no additional app registration or permissions required beyond Files.ReadWrite.All.

## Use cases

### Microsoft 365 document management in Bubble

Build a Bubble internal tool for Microsoft 365 teams where employees can browse OneDrive folders, view SharePoint document libraries, and access Teams channel files — all from a unified Bubble interface, without switching between Microsoft apps and your custom Bubble workflow app.

Prompt example:

```
Create a Bubble page where users select a Microsoft 365 site from a dropdown (fetched via GET /sites?search=), then see the site's document library contents in a repeating group (GET /sites/{siteId}/drive/root/children?$select=id,name,size,lastModifiedDateTime), and can generate sharing links for any file.
```

### Automated report distribution via OneDrive

When a Bubble workflow generates a report (PDF, CSV, or spreadsheet), automatically upload it to a specific OneDrive folder and create a sharing link — then email or Slack the link to stakeholders, keeping the file in the organization's official Microsoft storage.

Prompt example:

```
After a Bubble Backend Workflow finishes generating a monthly sales report CSV, call Graph API PUT /drives/{driveId}/root:/{year}/{month}/sales-report.csv:/content to upload it to OneDrive, then POST /drives/{driveId}/items/{newItemId}/createLink to get a shareable URL, and send the URL via email to the sales team.
```

### SharePoint document portal

Use Microsoft Graph to access SharePoint document libraries from a Bubble app — letting teams browse and download official company documents (policies, templates, procedures) stored in SharePoint without needing SharePoint access themselves.

Prompt example:

```
Build a Bubble page that fetches SharePoint site document libraries via GET /sites/{siteId}/drives, shows library names in a dropdown, and displays library contents in a repeating group with names, sizes, and last-modified dates. A 'Download' button generates a presigned download URL for the selected file.
```

## Troubleshooting

### Every Graph API call returns 403 'Insufficient privileges to complete the operation'

Cause: Admin consent has not been granted for the Files.ReadWrite.All permission in the Azure portal. Adding the permission to the app registration is not sufficient — a Global Administrator must explicitly approve it.

Solution: Go to portal.azure.com → Azure Active Directory → App registrations → find your app → API permissions. Check the Status column. If it shows 'Not granted', a Global Administrator must click 'Grant admin consent for {tenant name}'. If you are not the admin, contact your IT administrator with the Application ID and a request to grant consent. After consent is granted, retry the API call.

### Token exchange returns 401 or 'invalid_client' when calling the Microsoft token endpoint

Cause: The Client ID or Client Secret is incorrect, the tenant ID in the URL is wrong, or the Client Secret has expired.

Solution: In the Azure portal, go to App registrations → your app → Overview to confirm the Application (client) ID and Directory (tenant) ID. Go to Certificates & secrets — check if the client secret has an expiry date that has passed. If so, create a new secret, copy the Value immediately, and update the Bubble API Connector. Confirm the tenant ID in the token endpoint URL exactly matches the Directory (tenant) ID from the Overview page.

### API calls succeed for 60 minutes then fail with 401 'InvalidAuthenticationToken'

Cause: The cached Graph access token in the Bubble GraphConfig data type has expired. The Refresh Graph Token Backend Workflow is either not scheduled, not running on a paid Bubble plan, or failing silently.

Solution: Confirm you are on a paid Bubble plan — scheduled Backend Workflows are only available on paid plans. Go to Bubble Logs → Backend Workflow logs to verify the Refresh Graph Token workflow is running every 50 minutes. If it's not appearing, check Settings → API → Scheduled workflow. Also add a proactive expiry check before API calls: if GraphConfig's expires_at < Current date/time, trigger token refresh before proceeding.

### Initialize call for Graph API calls returns 'There was an issue setting up your call'

Cause: The access token used during initialization is expired, invalid, or the GraphConfig token cache hasn't been populated yet (the Refresh workflow hasn't run).

Solution: Run the Refresh Graph Token Backend Workflow manually once from the Bubble editor to populate the GraphConfig record with a fresh token. Then retry the Initialize call in the API Connector. The token must be valid and point to a real Microsoft 365 account with the required permissions. Check the Bubble Logs tab for the error detail from Graph's response.

### File listing call returns empty results or 'ItemNotFound' even though files exist in OneDrive

Cause: For client credentials (service account) flow: the service account (app identity) may not have been added as a Collaborator to the OneDrive being accessed, or is trying to access `/me/drive` which refers to the app's own drive (not a user's drive).

Solution: For client credentials flow, use `/users/{userId}/drive/root/children` instead of `/me/drive/root/children` — the `/me` path refers to the app service account, not a user. Get the target user's ID from Azure AD or from a prior call to `/users?$select=id,displayName`. Alternatively, if accessing SharePoint, use `/sites/{siteId}/drive/root/children`.

## Frequently asked questions

### What is admin consent and why can't I skip it?

Admin consent is Microsoft's mechanism for organizational IT administrators to approve which third-party apps can access company data. When an app requests Files.ReadWrite.All, it is asking for access to all files in the organization — a significant permission that Microsoft requires a Global Administrator to explicitly approve on behalf of the organization. Without admin consent, Microsoft refuses all API calls regardless of how correctly the app credentials are configured. This is a security requirement, not a bug, and cannot be bypassed.

### Can I access OneDrive on Bubble's free plan?

Not securely for the full server-to-server flow. Client-side API Connector calls work on the free plan but expose the access token in browser network requests. The secure pattern uses Backend Workflows for token management, which are only available on paid Bubble plans (Starter or above). Additionally, scheduled token refresh requires Backend Workflow scheduling — also a paid-plan feature.

### Does Graph API work for both personal OneDrive and business OneDrive?

The API is the same, but authentication differs. For Microsoft 365 Business/Education accounts (work or school accounts), you use the organizational tenant endpoint (`login.microsoftonline.com/{tenant-id}/oauth2/v2.0/token`) and admin consent is required. For personal Microsoft accounts (Outlook.com, Hotmail.com), you use the consumer endpoint (`login.microsoftonline.com/consumers`) and admin consent is not required. Most Bubble business apps target business accounts.

### Can I access SharePoint document libraries through the same integration?

Yes — this is one of Microsoft Graph's main advantages. The same API Connector, the same Bearer token, and the same Files.ReadWrite.All permission give you access to SharePoint document libraries via `/sites/{siteId}/drives` and `/drives/{driveId}/root/children`. You do not need a separate app registration, separate credentials, or separate API Connector group for SharePoint vs OneDrive — it's all unified under Microsoft Graph.

### How do I get files from a specific user's OneDrive in the client credentials flow?

With client credentials (service account), the `/me/drive` path refers to the app itself, not to a user. To access a specific user's OneDrive, use `/users/{userId}/drive` where `{userId}` is the user's Azure AD object ID or UPN (user principal name, usually their email). You can get user IDs from the Microsoft Graph Users API: `GET /users?$select=id,displayName,mail`. The service account must have Sites.Read.All or Files.ReadWrite.All permission for this to work.

### What happens when my Client Secret expires?

When the Azure AD Client Secret expires, token exchange calls fail and your entire integration stops working. Client secrets expire after the duration you set when creating them (typically 12-24 months). Set a calendar reminder 30 days before expiry: go to Azure portal → App registrations → your app → Certificates & secrets → create a new secret → update the Bubble API Connector with the new value → confirm the integration works → delete the old secret. Azure allows multiple active secrets simultaneously, enabling zero-downtime rotation.

---

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