Skip to main content
RapidDev - Software Development Agency
flutterflow-integrationsFlutterFlow API Call

Box

Connect FlutterFlow to Box using the FlutterFlow API Call method against Box API v2.0. Because Box's recommended server-to-server auth uses JWT signing with an RSA private key, the token must be minted by a Firebase Cloud Function or Supabase Edge Function — FlutterFlow then calls Box's REST API with that short-lived Bearer token to list folders, upload files, and generate shared links.

What you'll learn

  • Why Box JWT server authentication must run in a backend proxy and not directly in FlutterFlow
  • How to deploy a Firebase Cloud Function that returns Box access tokens securely
  • How to configure two FlutterFlow API groups for Box metadata and file uploads on separate hosts
  • How to list Box folder contents and display them in a FlutterFlow ListView
  • How to generate and display Box shared links from within your Flutter app
Book a free consultation
4.9Clutch rating
600+Happy partners
17+Countries served
190+Team members
Advanced17 min read60 minutesStorage & FilesLast updated July 2026RapidDev Engineering Team
TL;DR

Connect FlutterFlow to Box using the FlutterFlow API Call method against Box API v2.0. Because Box's recommended server-to-server auth uses JWT signing with an RSA private key, the token must be minted by a Firebase Cloud Function or Supabase Edge Function — FlutterFlow then calls Box's REST API with that short-lived Bearer token to list folders, upload files, and generate shared links.

Quick facts about this guide
FactValue
ToolBox
CategoryStorage & Files
MethodFlutterFlow API Call
DifficultyAdvanced
Time required60 minutes
Last updatedJuly 2026

Box in FlutterFlow: Enterprise File Management with JWT Auth

Box is built for enterprise content workflows — it powers secure file sharing, version control, and collaboration at scale for organizations of all sizes. When you add Box to a FlutterFlow app you unlock document upload flows, file browsers, contract sharing, and secure content distribution for your users. Box offers an Individual plan with 10 GB free, while Business plans start at around $15 per user per month (verify current pricing at box.com).

The most important thing to understand before you start: Box's recommended authentication for server apps is JWT server-to-server auth. This means your app signs a JSON assertion using an RSA private key from a downloaded config JSON file, exchanges it for a short-lived access token, and uses that token for all API calls. This signing step cannot be done safely inside a Flutter app — putting the RSA key or config JSON in Dart code or FlutterFlow API Call headers would expose it to anyone who inspects the compiled app bundle. The solution is a Firebase Cloud Function (or Supabase Edge Function) that holds the config and returns a fresh token whenever your FlutterFlow app requests one.

Once you have the proxy in place, the rest of the Box integration follows a clean REST pattern: one API Call group against api.box.com/2.0 for folder listing and shared link creation, and a second group against upload.box.com/api/2.0 for file uploads. Box returns clean JSON that maps easily to FlutterFlow ListViews and Text widgets, making it possible to build a fully functional file manager UI without additional Dart code.

Integration method

FlutterFlow API Call

FlutterFlow connects to Box API v2.0 (base URL: https://api.box.com/2.0) via API Call groups using a Bearer token fetched from a backend proxy. Box's preferred server-to-server JWT auth involves signing an assertion with an RSA private key, which cannot be done safely in Dart — so a Firebase Cloud Function or Supabase Edge Function holds the JWT config and returns short-lived access tokens to the Flutter app. File uploads go to a separate host (upload.box.com), so two API groups are needed.

Prerequisites

  • A Box account — Individual free plan (10 GB) works for testing; Business plan required for multi-user apps
  • A Firebase project (for Cloud Functions) or a Supabase project (for Edge Functions) already set up
  • Admin access to your Box account so you can authorize the custom app in Box Admin Console
  • A FlutterFlow project — any plan supports API Calls
  • Node.js installed locally to develop and deploy the Firebase Cloud Function (done outside FlutterFlow)

Step-by-step guide

1

Create a Box custom app with JWT server authentication

Open the Box Developer Console at developer.box.com and click 'Create New App'. Choose 'Custom App' and on the next screen select 'Server Authentication (with JWT)' — this is the option that allows your server to obtain tokens on behalf of the app or its users without user login prompts. Give your app a name such as 'MyFlutterFlowApp' and click 'Create App'. Once the app is created, open its Configuration tab. Under 'Application Access', choose 'App Access Only' for pure server-to-server operation (where your app manages all content) or 'App + Enterprise Access' if you want to act on behalf of managed Box users. Under 'Application Scopes', enable 'Read and write all files and folders stored in Box'. Scroll down to 'Add and Manage Public Keys' and click 'Generate a Public/Private Keypair' — this downloads a JSON config file containing your client ID, client secret, enterprise ID, and the RSA private key. Store this file securely in a password manager immediately — it is your signing credential and must never be committed to source control or placed inside FlutterFlow. Finally, go to the Box Admin Console (separate from the Developer Console), navigate to Apps → Custom Apps Manager, and click 'Authorize New App'. Paste your client ID and authorize it. Without this admin authorization step, JWT token requests will fail with an 'App not authorized' error even with a perfectly valid config file.

Pro tip: The downloaded config JSON is the only copy of your RSA private key. If you lose it or it is compromised, revoke and regenerate the keypair in the Developer Console immediately.

Expected result: Your Box custom app is created, has read/write scopes, a generated keypair config JSON is saved locally, and the app is authorized in the Box Admin Console.

2

Deploy a Firebase Cloud Function to proxy Box JWT tokens

Because Box JWT signing cannot happen in Dart, you need a small server function that holds the config JSON and returns a short-lived Box access token to your FlutterFlow app on request. Firebase Cloud Functions is the most common choice for FlutterFlow projects because many already use Firebase as a backend. In your Firebase project, go to the Functions section and create an HTTPS function. Install the official Box Node.js SDK (box-node-sdk) in your functions directory. Store your entire Box config JSON as a secret in Firebase Secret Manager — name it BOX_CONFIG. In your function code, parse the config, initialize the Box SDK using getPreconfiguredInstance, create an enterprise client, and exchange it for an access token. Return that token as JSON. Add Firebase Auth verification to the function so only authenticated app users can request Box tokens — without this guard, anyone who discovers your function URL could request tokens. The function receives the user's Firebase ID token in the Authorization header and verifies it before proceeding. Deploy the function and note its URL — you will paste this into a FlutterFlow API Call in the next step.

index.js
1// functions/index.js — Box token proxy
2const functions = require('firebase-functions');
3const admin = require('firebase-admin');
4const BoxSDK = require('box-node-sdk');
5
6admin.initializeApp();
7
8exports.getBoxToken = functions.https.onRequest(async (req, res) => {
9 // Verify Firebase ID token from Authorization header
10 const authHeader = req.headers.authorization || '';
11 const idToken = authHeader.replace('Bearer ', '');
12 try {
13 await admin.auth().verifyIdToken(idToken);
14 } catch (err) {
15 return res.status(401).json({ error: 'Unauthorized' });
16 }
17
18 try {
19 const configStr = process.env.BOX_CONFIG; // set via Firebase Secret Manager
20 const config = JSON.parse(configStr);
21 const sdk = BoxSDK.getPreconfiguredInstance(config);
22 const client = sdk.getAppAuthClient('enterprise');
23 const tokenInfo = await client.exchangeToken(['root_readwrite']);
24 res.json({ access_token: tokenInfo.accessToken });
25 } catch (err) {
26 console.error('Box token error:', err);
27 res.status(500).json({ error: 'Failed to get Box token' });
28 }
29});

Pro tip: Always verify the caller's Firebase ID token before returning a Box token — skip this check only when testing locally with a hard-coded test credential.

Expected result: Calling your Cloud Function URL with a valid Firebase ID token in the Authorization header returns a JSON object containing an access_token string.

3

Store the Box token in App State and build the token fetch action

In FlutterFlow, open the App State section from the left nav. Create a new String variable called boxAccessToken with an initial value of empty string. This variable will hold the short-lived token returned by your proxy function and will be referenced by the Authorization header in every Box API call. Next, create an API Call to your Firebase Cloud Function proxy. Click API Calls in the left nav → + Add → Create API Call (not API Group, since this is a single standalone endpoint). Name it 'GetBoxToken', set Method to POST, and paste your Cloud Function URL as the endpoint. In the Headers tab, add Authorization with value Bearer {{userFirebaseToken}} so you can pass the logged-in user's Firebase ID token. In Response & Test, test the call and generate the JSON Path $.access_token. In your app's initialization flow (for example, in the Page Load action of your home page), add an API Call action that calls GetBoxToken. Pass the current user's Firebase ID token (available in FlutterFlow as Authentication → Current User → JWT Token) as the userFirebaseToken variable. After the API Call action, add a Set App State action that sets boxAccessToken to the value at JSON Path $.access_token from the response. Box tokens expire after approximately one hour. For production apps, handle 401 responses by re-fetching the token automatically: add a conditional branch in your action flows that detects status code 401 from any Box API call, re-runs the GetBoxToken action, updates App State, and then retries the failed request.

Pro tip: Use App State (not Page State) for boxAccessToken so it persists across screen navigation without requiring a fresh proxy call on every page.

Expected result: After the initialization action runs, boxAccessToken in App State contains a valid Box Bearer token string ready for use in API headers.

4

Create two Box API Groups in FlutterFlow (metadata and upload)

Click API Calls in the left nav, then click + Add → Create API Group. Name it 'BoxMetadata' and set the Base URL to https://api.box.com/2.0. In the Headers tab of this group, add the shared header: Key = Authorization, Value = Bearer {{accessToken}}. Under Variables, add accessToken as a String variable — you will bind this to your boxAccessToken App State variable at call time. Inside the BoxMetadata group, add your first API Call: name it 'ListFolderItems', Method GET, Endpoint /folders/{{folderId}}/items?fields=id,name,type,size,modified_at. Add a Variable named folderId of type String. A critical note: Box's root folder ID is the string '0' (the digit zero) — not an empty string, not '/', just '0'. Passing anything else returns a 404. In Response & Test, paste a sample Box items response and click Generate JSON Paths to get paths like $.entries[*].id, $.entries[*].name, and $.entries[*].type. Add a second call inside BoxMetadata: name it 'CreateSharedLink', Method PUT, Endpoint /files/{{fileId}}, Content-Type application/json, Body {"shared_link": {"access": "open"}}. Add a Variable named fileId. For uploads, create a second API Group named 'BoxUpload' with Base URL https://upload.box.com/api/2.0. Add the same Authorization header. Inside, create an API Call named 'UploadFile', Method POST, Endpoint /files/content. Configure a multipart form body with two parts: one named 'attributes' containing the JSON string {"name":"{{fileName}}","parent":{"id":"{{parentId}}"}} and one named 'file' containing the binary content variable. This two-group setup is required because Box uses two different hostnames — mixing them causes 404 errors.

typescript
1// API Call reference (for documentation — enter these values in FlutterFlow UI)
2
3// BoxMetadata Group: https://api.box.com/2.0
4// Shared header: Authorization: Bearer {{accessToken}}
5
6// ListFolderItems
7// GET /folders/{{folderId}}/items?fields=id,name,type,size,modified_at
8// JSON Paths: $.entries[*].id | $.entries[*].name | $.entries[*].type
9// Root folderId = "0"
10
11// CreateSharedLink
12// PUT /files/{{fileId}}
13// Body: {"shared_link": {"access": "open"}}
14// Response JSON Path: $.shared_link.url
15
16// BoxUpload Group: https://upload.box.com/api/2.0
17// Shared header: Authorization: Bearer {{accessToken}}
18
19// UploadFile
20// POST /files/content
21// Multipart body:
22// attributes: {"name":"{{fileName}}","parent":{"id":"{{parentId}}"}}
23// file: [binary content]

Pro tip: Root folder ID in Box is always the string '0' — this is Box's most common gotcha and the first thing to check when listing returns a 404.

Expected result: Two API Groups appear in FlutterFlow: BoxMetadata (api.box.com/2.0) with ListFolderItems and CreateSharedLink calls, and BoxUpload (upload.box.com/api/2.0) with the UploadFile call.

5

Build the file browser UI and bind Box data to FlutterFlow widgets

Add a new page to your FlutterFlow project — call it 'BoxFiles'. Add a ListView widget to the page. In its Backend Query, select API Call → BoxMetadata → ListFolderItems. When prompted for variables, bind accessToken to your boxAccessToken App State variable and folderId to the page parameter (or hardcode '0' for the root folder). Inside the ListView template, add a Row widget containing an Icon and two Text widgets. Bind the first Text to $.entries[*].name and the second to $.entries[*].type. For the Icon, add a conditional that shows a folder icon when type is 'folder' and a document icon when type is 'file'. Add a tap action to the ListView item: use an If/Else action that branches on the type value. If type equals 'folder', navigate to the same BoxFiles page and pass the item's id as the folderId page parameter — this enables drill-down navigation. If type equals 'file', trigger the CreateSharedLink API Call with the item's id as the fileId. Extract $.shared_link.url from the response using a JSON Path action and then use a Launch URL action to open it. For the upload flow, add a floating action button with an Upload Media action (image or file picker). On completion, call BoxUpload → UploadFile with the selected file's bytes, the filename, and the current folderId as the parentId. On success, refresh the ListView using a Refresh widget action.

Pro tip: Use a Page Parameter (String) named folderId to pass the current folder ID through your navigation stack — start with '0' on the root screen.

Expected result: The BoxFiles page shows a scrollable list of files and folders from Box. Tapping a folder navigates into it; tapping a file opens its shared link. The upload button lets users add files to the current folder.

6

Test on a real device and handle enterprise authorization

Test the full flow in FlutterFlow's Run or Test mode for the API calls and navigation. The folder listing and shared link creation work fine in browser preview. However, file upload with a real binary payload is best verified on a real Android or iOS device (not just the canvas preview) because multipart binary handling can differ between the web preview and native builds. If you have just created your Box app, and JWT token requests return an error about authorization or an 'App not authorized' message, go back to Box Admin Console → Apps → Custom Apps and confirm the app appears in the authorized list. Enterprise Box accounts sometimes require the primary admin (not just any admin) to approve new apps — this step is easy to miss. For production deployments, also add token proactive refresh: when the boxAccessToken was last fetched more than 50 minutes ago (store a timestamp in App State alongside the token), automatically call GetBoxToken again before making Box API requests. This prevents mid-session 401 errors when users stay in the app longer than one hour. If the JWT proxy setup feels overwhelming to maintain alongside your FlutterFlow project, RapidDev's team builds FlutterFlow integrations including Box JWT setups every week — book a free scoping call at rapidevelopers.com/contact.

Pro tip: Store a lastTokenFetch timestamp in App State alongside boxAccessToken and proactively refresh the token if more than 50 minutes have elapsed.

Expected result: File listing, shared link generation, and file upload all work correctly on a real iOS or Android device. Token expiry is handled gracefully without crashing the session.

Common use cases

Client document portal for a consulting app

A consulting firm builds a client portal in FlutterFlow where each client can securely browse, review, and download contracts and deliverables stored in Box. The app fetches the client's dedicated Box folder, displays a file list, and generates time-limited shared links on demand.

FlutterFlow Prompt

Build a Flutter screen that lists all files in a specific Box folder and lets the user tap any file to open its shared link in a browser.

Copy this prompt to try it in FlutterFlow

Field service photo upload app

Field technicians use a FlutterFlow mobile app to photograph completed jobs and upload images directly to a shared Box folder organized by project. The app picks an image from the device gallery, uploads it to Box via the upload.box.com endpoint, and confirms the upload with a success banner.

FlutterFlow Prompt

Create a FlutterFlow screen with an image picker that uploads the selected photo to a Box folder using the Box Content API.

Copy this prompt to try it in FlutterFlow

Legal document request and delivery

A legal services app allows lawyers to request documents from clients and clients to upload signed forms back to a Box folder. The FlutterFlow interface shows pending documents, allows file selection and upload, and marks items as received once Box confirms the upload with a file entry in the listing.

FlutterFlow Prompt

Build a two-screen FlutterFlow app: one screen lists files in a Box folder and another lets the user upload a new file to that folder.

Copy this prompt to try it in FlutterFlow

Troubleshooting

401 Unauthorized on every Box API call immediately after fetching a token

Cause: The Box access token has not been applied to the Authorization header correctly, or the token value stored in App State contains extra whitespace or quotes from a JSON path extraction issue.

Solution: Open the BoxMetadata API Group in FlutterFlow and click Test on the ListFolderItems endpoint. Manually paste a fresh token from your proxy into the accessToken variable field. If the manual test succeeds but the app fails, the issue is in how the App State value is being set — verify your Set App State action uses the exact JSON Path $.access_token and check there are no extra quote characters around the stored value using a Debug Print action.

404 Not Found when listing the Box root folder

Cause: The folderId variable is being passed as an empty string, null, or '/' instead of the string '0'. Box's root folder ID is always the digit zero as a string character.

Solution: In the ListFolderItems API Call test in FlutterFlow, set folderId manually to 0 (the character zero). If that returns results, update your page parameter default or hardcoded value to '0'. Only pass other numeric ID strings (like '123456789') when navigating into specific subfolders returned from the listing.

File upload returns 400 Bad Request with a message about the 'attributes' part

Cause: Box's multipart upload requires both an 'attributes' JSON string part and a 'file' binary part. If the attributes part is missing or the JSON is malformed, Box rejects the upload.

Solution: Check your UploadFile API Call in FlutterFlow and confirm the multipart body has exactly two parts: one named 'attributes' with the JSON string value such as {"name":"photo.jpg","parent":{"id":"0"}}, and one named 'file' with the binary bytes variable. Do not manually set Content-Type to application/json — FlutterFlow handles the multipart/form-data boundary automatically.

Firebase Cloud Function returns 500 with 'App not authorized' in the Box SDK error

Cause: The Box custom app has not been authorized in the Box Admin Console, which is a mandatory step separate from creating the app in the Developer Console.

Solution: Log in to your Box Admin Console (admin.app.box.com), navigate to Apps → Custom Apps Manager, click 'Authorize New App', and enter your app's client ID. After authorization, retry the Cloud Function — the error should resolve immediately without redeploying the function.

Best practices

  • Never store the Box JWT config JSON or RSA private key inside FlutterFlow, Dart code, or App State — keep it exclusively in Firebase Secret Manager or Supabase Vault
  • Add Firebase Auth ID token verification to your Cloud Function proxy so only authenticated app users can request Box tokens
  • Proactively refresh the Box access token after 50 minutes in App State — tokens expire at 60 minutes and a proactive refresh prevents mid-session 401 errors
  • Always pass '0' (the digit zero as a string) as folderId for Box's root folder — empty string and '/' both return 404
  • Use two separate API Groups in FlutterFlow: BoxMetadata for api.box.com/2.0 and BoxUpload for upload.box.com/api/2.0 — mixing hosts returns 404
  • Request only the Box scopes your app genuinely needs: 'root_readwrite' gives full access; for read-only file browsers prefer 'root_readonly' to limit exposure
  • Verify file uploads on a real device rather than the FlutterFlow canvas preview — multipart binary upload behavior can differ in the browser-based editor
  • Store the current Box folder ID in a Page Parameter rather than hardcoding it, so users can navigate into subfolders through your drill-down UI

Alternatives

Frequently asked questions

Can I use Box OAuth 2.0 user login instead of JWT server auth in FlutterFlow?

Yes — Box also supports standard OAuth 2.0 where the user logs into Box directly and your app receives an access token tied to their account. This avoids the RSA signing requirement but still needs a backend to hold the client secret and handle the authorization code exchange. For apps where users bring their own Box accounts, user OAuth is actually simpler than JWT; JWT is best for apps where your organization owns all the Box content.

Does Box charge per API call?

Box pricing is primarily per user per month based on plan — Individual is free at 10 GB, and Business plans start around $15 per user per month (verify current pricing at box.com). Standard API usage is included within plan limits. Very high API volumes in enterprise scenarios may require a custom Enterprise plan discussion with Box sales.

Will the Box integration work on iOS, Android, and FlutterFlow web builds?

Yes. Box API endpoints support CORS for browser origins, so web builds can call the metadata API directly once your app holds a valid token. File uploads from a web build use the same multipart call. On native iOS and Android builds there are no CORS constraints. The JWT token proxy must always run server-side regardless of target platform — this is a security requirement, not a platform limitation.

What is the maximum file size I can upload to Box from FlutterFlow?

The simple single-request upload (POST /files/content to upload.box.com) supports files up to approximately 50 MB. For larger files, Box requires a chunked upload session: first call /files/upload_sessions, then upload parts sequentially, and finally commit. Chunked uploads are best implemented in a Custom Action (Dart) rather than standard API Calls because they require multi-step binary state management that is difficult to express in FlutterFlow's action flow editor.

Why do I need to authorize my Box app in the Admin Console after creating it?

Box separates developer actions (creating and configuring an app) from enterprise admin actions (permitting an app to access the organization's content). This two-step design is a security control so that developers cannot self-authorize apps against enterprise Box accounts without an admin explicitly reviewing and approving each app. If you are both the developer and the admin, you will simply need to complete both steps yourself.

RapidDev

Talk to an Expert

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

Book a free consultation

Integrations are where projects stall

We wire FlutterFlow integrations like this one every week — auth, webhooks, edge cases included. Fixed-price builds from $13K, delivered in 6–10 weeks.

Talk to an integration engineer

We put the rapid in RapidDev

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