# OneDrive

- Tool: FlutterFlow
- Difficulty: Advanced
- Time required: 90 minutes
- Last updated: July 2026

## TL;DR

Connect FlutterFlow to OneDrive by building a Microsoft Graph API Group with a shared Authorization header. Because the Azure AD OAuth token exchange uses a client secret, deploy a Firebase Cloud Function or Supabase Edge Function to handle the exchange server-side — your FlutterFlow app stores only the short-lived access token in App State, never the secret.

## OneDrive in FlutterFlow: Microsoft Graph, OAuth, and a mandatory backend proxy

OneDrive is not a standalone file API — every file operation goes through the Microsoft Graph platform at graph.microsoft.com/v1.0. Listing files is a GET /me/drive/root/children, uploading is a PUT /me/drive/root:/{filename}:/content, and generating a shareable link is a POST to /me/drive/items/{id}/createLink. All of these calls require a Bearer access token issued by Azure Active Directory.

The critical FlutterFlow constraint: that access token is produced by exchanging an OAuth authorization code for a token using your app's client secret. A client secret embedded in a compiled Flutter app is extractable from the binary by anyone who installs it. The correct pattern is a backend function — a Firebase Cloud Function or a Supabase Edge Function — that holds the client secret, performs the code-for-token exchange, and returns only the short-lived access token to FlutterFlow. Your app stores that token in App State and passes it as a Bearer header on every Graph call.

OneDrive's free plan gives 5 GB per Microsoft account; Microsoft 365 Personal starts around $1.99/month for 100 GB (verify current pricing at microsoft.com). Business plans bundle 1 TB per user. Graph rate limits are per-app and per-user; Microsoft returns 429 with a Retry-After header when limits are exceeded — check current quotas in the Microsoft Graph documentation.

## Before you start

- A Microsoft Azure account (free at portal.azure.com)
- A FlutterFlow project (API Calls are available on all plans)
- A Firebase project (for the Cloud Function proxy) or a Supabase project (for the Edge Function proxy)
- Basic familiarity with FlutterFlow's App State and Action Flow Editor
- A short Node.js or Deno/TypeScript snippet for the backend function (provided in the steps)

## Step-by-step guide

### 1. Register an Azure AD application and configure the Files.ReadWrite.All scope

Open portal.azure.com in your browser. In the top search bar, type App registrations and click the result. Click New registration. Give the app a name like FlutterFlow OneDrive App. For Supported account types, choose Accounts in any organizational directory and personal Microsoft accounts — this covers personal OneDrive as well as work accounts. In the Redirect URI field, enter the URL of your backend proxy function (for example https://us-central1-your-project.cloudfunctions.net/oneDriveAuth). Click Register.

Once created, copy the Application (client) ID and the Directory (tenant) ID shown on the overview page — you will need both. In the left sidebar, click Certificates & secrets. Click New client secret, give it a description and an expiry period, then click Add. Copy the Value immediately — it is shown only once and is your client secret. This value must never leave your backend function.

Next, click API permissions in the left sidebar → Add a permission → Microsoft Graph → Delegated permissions. Search for Files and check Files.ReadWrite.All. Click Add permissions. For apps that also access shared drives or SharePoint, add Sites.Read.All. Individual users will consent to these permissions during the OAuth flow, so admin consent is not required for personal OneDrive scenarios.

**Expected result:** You have an Azure AD app with an Application ID, tenant ID, a redirect URI pointing at your backend function, and Files.ReadWrite.All permission configured.

### 2. Deploy a token-exchange backend proxy that holds the Azure client secret

Because the Azure AD token endpoint requires your client secret, this step runs entirely outside FlutterFlow on a backend you control. You will deploy a small HTTP function that accepts the OAuth authorization code returned to the user's browser, exchanges it for an access token using the Azure token endpoint, and returns only the access token to FlutterFlow.

In the Firebase console, open Functions and create a new HTTP function named oneDriveAuth (or use Supabase Edge Functions if that is your backend). The function accepts a POST request with a code parameter, calls https://login.microsoftonline.com/{tenant}/oauth2/v2.0/token with your client secret, and returns the access_token in the response JSON. Create a second function named oneDriveRefresh that accepts a refresh token, calls the same endpoint with grant_type=refresh_token, and returns a fresh access_token. Store the refresh token server-side — keyed to the user's identifier — and do NOT send it to FlutterFlow.

Deploy both functions and note their public HTTPS URLs. Restrict them with a shared API secret header so only your app can call them.

```
// Firebase Cloud Function — token exchange proxy
// functions/index.js (Node.js)
const functions = require('firebase-functions');
const axios = require('axios');

const CLIENT_ID = functions.config().azure.client_id;
const CLIENT_SECRET = functions.config().azure.client_secret;
const TENANT_ID = functions.config().azure.tenant_id;
const REDIRECT_URI = functions.config().azure.redirect_uri;

exports.oneDriveAuth = functions.https.onRequest(async (req, res) => {
  res.set('Access-Control-Allow-Origin', '*');
  if (req.method === 'OPTIONS') return res.status(204).send('');
  if (req.method !== 'POST') return res.status(405).send('Method Not Allowed');

  const { code } = req.body;
  if (!code) return res.status(400).json({ error: 'Missing code' });

  const params = new URLSearchParams({
    client_id: CLIENT_ID,
    client_secret: CLIENT_SECRET,
    code,
    redirect_uri: REDIRECT_URI,
    grant_type: 'authorization_code',
    scope: 'Files.ReadWrite.All offline_access',
  });

  try {
    const tokenRes = await axios.post(
      `https://login.microsoftonline.com/${TENANT_ID}/oauth2/v2.0/token`,
      params.toString(),
      { headers: { 'Content-Type': 'application/x-www-form-urlencoded' } }
    );
    // Store refreshToken in Firestore; return only access_token
    res.json({ access_token: tokenRes.data.access_token });
  } catch (err) {
    res.status(500).json({ error: err.message });
  }
});
```

**Expected result:** Two deployed Cloud Function URLs — one for the initial code exchange (/oneDriveAuth) and one for refresh (/oneDriveRefresh) — that return an access token without exposing the Azure client secret.

### 3. Build the OAuth sign-in flow in FlutterFlow and store the access token in App State

In FlutterFlow, go to App State in the left nav and create two variables: accessToken (Type: String, default empty) and tokenExpiry (Type: Integer, default 0 — stores the Unix timestamp of expiry). These variables persist across pages and power every Graph API call.

Create a new page called OneDriveLogin. Add a Button labeled Sign in with Microsoft. In the Action Flow Editor for that button, add a Launch URL action that opens the Azure authorization URL:
https://login.microsoftonline.com/common/oauth2/v2.0/authorize?client_id=YOUR_CLIENT_ID&response_type=code&redirect_uri=YOUR_FUNCTION_URL&scope=Files.ReadWrite.All+offline_access&response_mode=query

The redirect URI points to your backend function. After the function exchanges the code for a token, it can redirect the user back to your app via a deep link (for example myapp://auth?token=ACCESS_TOKEN). In FlutterFlow, configure deep links under Settings & Integrations → Mobile Deployment → Deep Links. On web builds, the function can redirect to a /auth-callback page that reads the token from a URL query parameter using a Custom Action.

On the callback page, add an On Page Load action that reads the token from the URL query parameters and calls Set App State to save it to accessToken. Also save the current timestamp plus 3,540 seconds (59 minutes) to tokenExpiry so you know when to refresh. Navigate the user to the main file browser page after the state is saved.

**Expected result:** Users can tap Sign in with Microsoft, complete the OAuth consent flow in a browser, and return to the app with a valid access token and expiry time stored in App State.

### 4. Create the MSGraph API Group in FlutterFlow with file list, upload, and share endpoints

In the FlutterFlow left nav, click API Calls → + Add → Create API Group. Name it MSGraph and set the base URL to https://graph.microsoft.com/v1.0. In the Headers tab, add one header: Key = Authorization, Value = Bearer [accessToken]. Click the small variable chip next to the value field and select App State → accessToken. This dynamically injects the token into every call in this group.

Now add your first API Call. Click MSGraph → + Add API Call. Name it listDriveFiles. Set the method to GET and the endpoint to /me/drive/root/children. Switch to the Response & Test tab, paste a sample Graph response (a JSON object with a value array of DriveItem objects), and click Generate JSON Path. FlutterFlow will produce paths like $.value[*].name, $.value[*].id, $.value[*].webUrl, and $.value[*].lastModifiedDateTime.

Add a second API Call named uploadFile. Method = PUT, endpoint = /me/drive/root:/{{filename}}:/content. In the Variables tab, add a filename variable (String) and a fileContent variable (String for base64). Set the body type to Binary and bind fileContent.

Add a third API Call named createShareLink. Method = POST, endpoint = /me/drive/items/{{itemId}}/createLink. Add an itemId variable. Body = {"type":"view","scope":"anonymous"}. In the Response & Test tab, add JSON path $.link.webUrl to capture the shareable URL.

```
// API Group reference — MSGraph
{
  "base_url": "https://graph.microsoft.com/v1.0",
  "headers": {
    "Authorization": "Bearer {{accessToken}}"
  },
  "calls": [
    {
      "name": "listDriveFiles",
      "method": "GET",
      "endpoint": "/me/drive/root/children",
      "json_paths": [
        "$.value[*].name",
        "$.value[*].id",
        "$.value[*].webUrl",
        "$.value[*].lastModifiedDateTime"
      ]
    },
    {
      "name": "uploadFile",
      "method": "PUT",
      "endpoint": "/me/drive/root:/{{filename}}:/content",
      "body_type": "binary"
    },
    {
      "name": "createShareLink",
      "method": "POST",
      "endpoint": "/me/drive/items/{{itemId}}/createLink",
      "body": { "type": "view", "scope": "anonymous" },
      "json_paths": ["$.link.webUrl"]
    }
  ]
}
```

**Expected result:** An MSGraph API Group with three endpoints appears in the API Calls panel, all sharing the Authorization header bound to App State.

### 5. Bind the file list to a ListView and wire the upload and share actions

Navigate to your main files page. Add a ListView widget. In the Backend Query panel on the right, select API Call → MSGraph → listDriveFiles. Set the list source to the $.value JSON path (the array of DriveItem objects). FlutterFlow will iterate over the array to populate the ListView.

Inside the ListView, add a Column containing a Text widget bound to $.name (file name) and a subtitle Text widget bound to $.lastModifiedDateTime. Add an icon button (share icon) at the end of the row. For the share button's action, add a Backend/API Call action → MSGraph → createShareLink, binding itemId to the current list item's $.id. After the call succeeds, add a Copy to Clipboard action bound to the API response JSON path $.link.webUrl, and show a Snackbar with the message Link copied.

For uploading, add a FilePicker action to a dedicated Upload button. This returns the selected file as bytes and a file name. Store them in Page State variables (fileBytes and fileName). Then add a Backend/API Call action → MSGraph → uploadFile, binding filename to the fileName Page State variable and fileContent to the fileBytes variable. After a successful upload (response code 200 or 201), trigger a ListView refresh by re-running the listDriveFiles backend query.

Note: for files larger than 4 MB, the simple PUT returns a 413 or 400 error. You will need to first call POST /me/drive/root:/{filename}:/createUploadSession (add a fourth API Call for this) to get a one-time uploadUrl, then PUT file chunks to that URL. This multi-step flow is most reliably implemented as a Custom Action in Dart.

**Expected result:** The ListView displays OneDrive files by name and modification date. Users can share a file by tapping its share button, and upload new files using the file picker button.

### 6. Test on a real device and implement proactive token refresh

The OAuth deep-link redirect only works in a real built app (APK, TestFlight, or published web). Use FlutterFlow's Run mode to generate a quick test build. During active development, bypass the sign-in flow by manually populating the accessToken App State variable with a temporary token from Microsoft Graph Explorer (developer.microsoft.com/graph/graph-explorer) — retrieve one there in two clicks. Remove that hard-coded token before your production release.

For production token refresh, add a Custom Action to FlutterFlow: in the left nav → Custom Code → + Add → Action. Name it refreshOneDriveToken. This Dart action reads the tokenExpiry from App State, checks if the current Unix timestamp is within 600 seconds of expiry, and if so makes an HTTP POST to your /oneDriveRefresh Cloud Function URL. The function returns a new access_token; the action saves it to App State accessToken and updates tokenExpiry.

Call this Custom Action in an On Page Load trigger on every page that uses OneDrive data, before any API Calls run. This keeps the session alive transparently without the user needing to re-authenticate more than once per session.

If setting up and maintaining the OAuth proxy and token refresh infrastructure feels like too much for your current stage, the RapidDev team handles FlutterFlow integrations like this regularly — book a free scoping call at rapidevelopers.com/contact.

```
// Custom Action: refreshOneDriveToken
// FlutterFlow Custom Code → + Add → Action
import 'package:http/http.dart' as http;
import 'dart:convert';

Future refreshOneDriveToken() async {
  final expiry = FFAppState().tokenExpiry; // Unix timestamp
  final now = DateTime.now().millisecondsSinceEpoch ~/ 1000;
  if (expiry - now > 600) return; // Still valid for 10+ minutes

  const refreshUrl = 'https://us-central1-your-project.cloudfunctions.net/oneDriveRefresh';
  final response = await http.post(
    Uri.parse(refreshUrl),
    headers: {'Content-Type': 'application/json'},
    body: jsonEncode({'uid': FFAppState().currentUserId}),
  );

  if (response.statusCode == 200) {
    final data = jsonDecode(response.body);
    FFAppState().update(() {
      FFAppState().accessToken = data['access_token'];
      FFAppState().tokenExpiry =
          DateTime.now().millisecondsSinceEpoch ~/ 1000 + 3540;
    });
  }
}
```

**Expected result:** The app completes OAuth sign-in on a real device, refreshes the token automatically before it expires, and users never see unexpected 401 errors during a session.

## Best practices

- Never put the Azure AD client secret or refresh token inside FlutterFlow — always route the OAuth token exchange through a Firebase Cloud Function or Supabase Edge Function.
- Store the access token's expiry timestamp in App State alongside the token itself, and refresh proactively before expiry rather than waiting for a 401 error.
- Request only the minimum scope needed: use Files.Read if your app only displays files, and add Files.ReadWrite only when users need to upload or modify files.
- Handle 429 Too Many Requests responses from Graph by reading the Retry-After header and adding a delay before retrying — Graph throttles per-app and per-user under load.
- For files larger than 4 MB, always use the createUploadSession + chunked PUT flow — the simple PUT endpoint silently fails for large payloads.
- Use platform-appropriate redirect URIs: a deep link scheme for mobile (myapp://auth) and an HTTPS callback page for web builds.
- Test all Graph API calls with Graph Explorer first to confirm the exact response shape before building JSON path bindings in FlutterFlow.

## Use cases

### Document management app for consultants

A FlutterFlow app that lets consultants browse, upload, and share client deliverables stored in their personal or shared OneDrive. The app uses the Graph API to list files, generate shareable links, and upload new versions directly from a mobile device. Access tokens refresh silently via the Cloud Function proxy.

Prompt example:

```
Build a document management screen that lists OneDrive folders, lets users tap to open files in a WebView, and includes a floating action button to upload a new PDF from the device's file picker.
```

### Field service app with automatic photo sync to OneDrive

A FlutterFlow app used by field technicians to capture photos on-site and automatically sync them to a OneDrive folder named after the job number. Photos taken in low-connectivity areas are queued locally and uploaded when a connection is restored. The Graph API's simple PUT endpoint handles files up to 4 MB without additional setup.

Prompt example:

```
Create a FlutterFlow page where technicians can select a job, take a photo, and upload it to a OneDrive subfolder named after the job ID, showing an upload progress indicator.
```

### Team marketing asset library

A FlutterFlow app that gives a marketing team read-only access to a shared OneDrive drive containing brand assets — logos, templates, and campaign images. The app lists folders, renders image thumbnails using the Graph thumbnail endpoint, and lets users copy the shareable link to their clipboard.

Prompt example:

```
Build a marketing asset browser that shows a grid of image thumbnails from a shared OneDrive folder, with a long-press to copy the shareable URL to the clipboard.
```

## Troubleshooting

### API Call returns 401 Unauthorized immediately after sign-in

Cause: The access token was not saved to App State before the API Call fired, or the Authorization header in the API Group is not binding the App State variable correctly.

Solution: Open API Calls → MSGraph → Headers tab and confirm the Authorization value shows Bearer {{accessToken}} with the App State variable chip, not a literal text string. In the sign-in action flow, ensure the Set App State action for accessToken runs BEFORE any API Call actions.

### Access token expires mid-session and all Graph calls suddenly return 401

Cause: Azure AD access tokens expire in approximately one hour. Without a proactive refresh mechanism, the stored token becomes invalid while the user is still using the app.

Solution: Add the refreshOneDriveToken Custom Action (from Step 6) to the On Page Load trigger of every page that calls the Graph API. This silently refreshes the token before any API Call runs, preventing mid-session 401 errors.

### File upload returns 400 Bad Request or 413 Payload Too Large

Cause: The simple PUT /me/drive/root:/{filename}:/content endpoint only supports files up to 4 MB. Files over that size must use a chunked upload session.

Solution: For files over 4 MB, first call POST /me/drive/root:/{filename}:/createUploadSession to receive a one-time uploadUrl. Then split the file bytes into 4 MB chunks and PUT each chunk with the Content-Range header. Implement this in a Custom Action (Dart) rather than a sequence of individual API Calls.

### listDriveFiles returns an empty value array even though files exist

Cause: GET /me/drive/root/children lists only the root level of the user's OneDrive. If all files are inside subfolders, or if the Files.ReadWrite.All permission was not properly consented, the response will appear empty or return a 403.

Solution: Test the exact same call in Microsoft Graph Explorer with your token to verify the response. To list a subfolder, change the endpoint to /me/drive/root:/FolderName:/children. If you see a 403 Forbidden error, check the Azure portal to confirm the Files.ReadWrite.All scope is granted and that no Conditional Access policy is blocking the token.

## Frequently asked questions

### Can I use OneDrive with personal Microsoft accounts, not just corporate Azure AD?

Yes. When registering the app in the Azure portal, choose Accounts in any organizational directory and personal Microsoft accounts as the supported account type. Use common as the tenant ID in the OAuth authorization URL. Personal OneDrive uses the exact same /me/drive endpoints as work accounts.

### Does the Microsoft Graph API support CORS for FlutterFlow web builds?

Yes, Graph endpoints include CORS headers in their responses, so listDriveFiles and other metadata calls work directly from a browser-based FlutterFlow web build. The only part that must stay on the backend is the OAuth token exchange, because it requires the client secret.

### What happens if the user's OneDrive storage is full when my app tries to upload?

Graph returns 507 Insufficient Storage. Add error handling in your upload action flow: check the API response code and display a user-friendly message like Your OneDrive storage is full when you receive a 507. You can also pre-check quota by calling GET /me/drive and reading the quota.remaining field before attempting the upload.

### Can I access a shared SharePoint library instead of the user's personal OneDrive?

Yes, but the endpoint changes to /drives/{driveId}/items/{itemId}/children instead of /me/drive/root/children. You first discover the drive ID by calling /sites/{siteId}/drives. Add Sites.Read.All to your Azure app permissions. The FlutterFlow API Group structure is the same — you just add a driveId variable to the endpoint.

### How do I show file thumbnails in FlutterFlow for OneDrive images?

Append ?$expand=thumbnails to the listDriveFiles endpoint, for example /me/drive/root/children?$expand=thumbnails. The response will include a thumbnails array on each DriveItem. Use the JSON path $.value[*].thumbnails[0].medium.url and bind it to an Image widget's URL property inside your ListView.

---

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