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.
| Fact | Value |
|---|---|
| Tool | OneDrive |
| Category | Storage & Files |
| Method | FlutterFlow API Call |
| Difficulty | Advanced |
| Time required | 90 minutes |
| Last updated | July 2026 |
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.
Integration method
FlutterFlow talks to Microsoft Graph (https://graph.microsoft.com/v1.0) using a Bearer access token stored in App State. Because Azure AD requires a client secret to exchange an auth code for a token — and that secret cannot safely live inside a compiled Flutter app — a backend proxy handles the OAuth exchange and token refresh. FlutterFlow only ever holds the short-lived access token.
Prerequisites
- 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
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.
Pro tip: Use a tenant value of common in the OAuth URL if you want both personal Microsoft accounts and work/school accounts to sign in. Use consumers for personal accounts only.
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.
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.
1// Firebase Cloud Function — token exchange proxy2// functions/index.js (Node.js)3const functions = require('firebase-functions');4const axios = require('axios');56const CLIENT_ID = functions.config().azure.client_id;7const CLIENT_SECRET = functions.config().azure.client_secret;8const TENANT_ID = functions.config().azure.tenant_id;9const REDIRECT_URI = functions.config().azure.redirect_uri;1011exports.oneDriveAuth = functions.https.onRequest(async (req, res) => {12 res.set('Access-Control-Allow-Origin', '*');13 if (req.method === 'OPTIONS') return res.status(204).send('');14 if (req.method !== 'POST') return res.status(405).send('Method Not Allowed');1516 const { code } = req.body;17 if (!code) return res.status(400).json({ error: 'Missing code' });1819 const params = new URLSearchParams({20 client_id: CLIENT_ID,21 client_secret: CLIENT_SECRET,22 code,23 redirect_uri: REDIRECT_URI,24 grant_type: 'authorization_code',25 scope: 'Files.ReadWrite.All offline_access',26 });2728 try {29 const tokenRes = await axios.post(30 `https://login.microsoftonline.com/${TENANT_ID}/oauth2/v2.0/token`,31 params.toString(),32 { headers: { 'Content-Type': 'application/x-www-form-urlencoded' } }33 );34 // Store refreshToken in Firestore; return only access_token35 res.json({ access_token: tokenRes.data.access_token });36 } catch (err) {37 res.status(500).json({ error: err.message });38 }39});40Pro tip: Run firebase functions:config:set azure.client_secret=YOUR_SECRET to keep the secret out of source code and committed files.
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.
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.
Pro tip: During development, skip the OAuth flow by manually fetching a short-lived token from Microsoft Graph Explorer (developer.microsoft.com/graph/graph-explorer) and pasting it into the App State default value.
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.
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.
1// API Group reference — MSGraph2{3 "base_url": "https://graph.microsoft.com/v1.0",4 "headers": {5 "Authorization": "Bearer {{accessToken}}"6 },7 "calls": [8 {9 "name": "listDriveFiles",10 "method": "GET",11 "endpoint": "/me/drive/root/children",12 "json_paths": [13 "$.value[*].name",14 "$.value[*].id",15 "$.value[*].webUrl",16 "$.value[*].lastModifiedDateTime"17 ]18 },19 {20 "name": "uploadFile",21 "method": "PUT",22 "endpoint": "/me/drive/root:/{{filename}}:/content",23 "body_type": "binary"24 },25 {26 "name": "createShareLink",27 "method": "POST",28 "endpoint": "/me/drive/items/{{itemId}}/createLink",29 "body": { "type": "view", "scope": "anonymous" },30 "json_paths": ["$.link.webUrl"]31 }32 ]33}34Pro tip: Microsoft Graph supports CORS, so these API Calls work in FlutterFlow's web preview mode as long as the accessToken App State variable is already populated.
Expected result: An MSGraph API Group with three endpoints appears in the API Calls panel, all sharing the Authorization header bound to App State.
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.
Pro tip: Add a Conditional Visibility on a CircularProgressIndicator widget that shows while the upload API Call is in progress — bind it to the isFetching state of the uploadFile call.
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.
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.
1// Custom Action: refreshOneDriveToken2// FlutterFlow Custom Code → + Add → Action3import 'package:http/http.dart' as http;4import 'dart:convert';56Future refreshOneDriveToken() async {7 final expiry = FFAppState().tokenExpiry; // Unix timestamp8 final now = DateTime.now().millisecondsSinceEpoch ~/ 1000;9 if (expiry - now > 600) return; // Still valid for 10+ minutes1011 const refreshUrl = 'https://us-central1-your-project.cloudfunctions.net/oneDriveRefresh';12 final response = await http.post(13 Uri.parse(refreshUrl),14 headers: {'Content-Type': 'application/json'},15 body: jsonEncode({'uid': FFAppState().currentUserId}),16 );1718 if (response.statusCode == 200) {19 final data = jsonDecode(response.body);20 FFAppState().update(() {21 FFAppState().accessToken = data['access_token'];22 FFAppState().tokenExpiry =23 DateTime.now().millisecondsSinceEpoch ~/ 1000 + 3540;24 });25 }26}27Pro tip: Custom Actions run in Run mode and real builds, but not in the instant canvas preview. Test the refresh action using Run mode or a device build.
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.
Common 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.
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.
Copy this prompt to try it in FlutterFlow
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.
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.
Copy this prompt to try it in FlutterFlow
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.
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.
Copy this prompt to try it in FlutterFlow
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.
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.
Alternatives
Dropbox uses a simpler Bearer token without Azure AD tenant complexity, making it faster to prototype if your users don't already rely on Microsoft 365.
Backblaze B2 is developer-focused object storage that is cheaper per GB and better suited for app-generated files when you control the storage bucket rather than reading from a user's personal cloud.
Wasabi is an S3-compatible store with no egress fees — ideal for media-heavy apps where you own the storage instead of connecting to each user's personal OneDrive.
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.
Talk to an Expert
Our team has built 600+ apps. Get personalized help with your project.
Book a free consultation