# How to Set Up a Secure File Sharing System in FlutterFlow

- Tool: FlutterFlow
- Difficulty: Beginner
- Time required: 25-35 min
- Compatibility: FlutterFlow Pro+ (Cloud Functions for signed URL generation)
- Last updated: March 2026

## TL;DR

Build a secure file sharing system using Firebase Storage for uploads and Cloud Functions for access-controlled downloads. Files are shared via links with optional password protection and expiry dates. Every download goes through a Cloud Function that verifies the requester's access (userId in sharedWith array or correct password) before generating a short-lived signed URL (15-minute expiry). Never expose permanent Storage download URLs directly. Track download counts and show file owners a dashboard of shared files with access logs.

## Building Access-Controlled File Sharing in FlutterFlow

Sharing files securely means more than just uploading to cloud storage. Permanent download URLs can be forwarded to anyone, bypassing your access controls. This tutorial builds a sharing system where every download is verified by a Cloud Function that checks permissions, passwords, and expiry before generating a time-limited signed URL.

## Before you start

- FlutterFlow project with Firebase authentication
- Firebase Storage configured with security rules
- Cloud Functions enabled on your Firebase project
- Basic understanding of Firebase Storage in FlutterFlow

## Step-by-step guide

### 1. Create the Firestore schema for shared files

Create a shared_files collection with fields: uploaderId (String), filename (String), storagePath (String, the Firebase Storage path), size (int, bytes), mimeType (String), sharedWith (list of Strings, userIds or 'public'), password (String, hashed, optional), expiresAt (Timestamp, optional), downloadCount (int, default 0), createdAt (Timestamp). The storagePath stores the internal Storage path, never the direct download URL. The sharedWith array controls who can access the file. Setting it to ['public'] allows anyone with the link. An optional password adds a second layer of protection. The expiresAt field makes links expire after a set date.

**Expected result:** Firestore has a shared_files collection with access control, password, and expiry fields.

### 2. Build the file upload and sharing configuration form

Create an UploadFile page with a FlutterFlowUploadButton configured for the file types you want to support (documents, images, PDFs). After upload, the button returns the Storage file path. Below the upload button, add sharing options: a Switch for public vs private sharing, a TextField for entering userIds or email addresses to share with (for private), a Switch to enable password protection with a TextField for the password, and a DateTimePicker for optional expiry date. The Share button creates the shared_files Firestore document with all configured options and generates a shareable link (your app URL + the shared_files document ID).

**Expected result:** Users upload files and configure sharing options including access list, optional password, and expiry date.

### 3. Deploy the Cloud Function for secure download URL generation

Create a Cloud Function called getSecureDownloadUrl that receives the shared file document ID and optionally a password. The function reads the shared_files document from Firestore and performs access checks: verify the requester is authenticated, check if their userId is in the sharedWith array or if sharedWith contains 'public', verify the password hash matches if password protection is enabled, and check if the current time is before expiresAt. If all checks pass, generate a signed URL for the Storage file with a 15-minute expiry using the Firebase Admin SDK's getSignedUrl method. Increment the downloadCount field. Return the signed URL to the client.

```
// Cloud Function: getSecureDownloadUrl
const functions = require('firebase-functions');
const admin = require('firebase-admin');
const crypto = require('crypto');
admin.initializeApp();

exports.getSecureDownloadUrl = functions.https
  .onCall(async (data, context) => {
    const { fileId, password } = data;
    const uid = context.auth?.uid;
    
    const fileDoc = await admin.firestore()
      .collection('shared_files').doc(fileId).get();
    if (!fileDoc.exists) throw new functions.https
      .HttpsError('not-found', 'File not found');
    
    const file = fileDoc.data();
    
    // Check expiry
    if (file.expiresAt && file.expiresAt.toDate() < new Date()) {
      throw new functions.https
        .HttpsError('deadline-exceeded', 'Link expired');
    }
    
    // Check access
    const isPublic = file.sharedWith.includes('public');
    const isAuthorized = uid && file.sharedWith.includes(uid);
    const isOwner = uid === file.uploaderId;
    if (!isPublic && !isAuthorized && !isOwner) {
      throw new functions.https
        .HttpsError('permission-denied', 'No access');
    }
    
    // Check password
    if (file.password) {
      const hash = crypto.createHash('sha256')
        .update(password || '').digest('hex');
      if (hash !== file.password) {
        throw new functions.https
          .HttpsError('permission-denied', 'Wrong password');
      }
    }
    
    // Generate signed URL (15 min expiry)
    const bucket = admin.storage().bucket();
    const [url] = await bucket.file(file.storagePath)
      .getSignedUrl({
        action: 'read',
        expires: Date.now() + 15 * 60 * 1000,
      });
    
    // Track download
    await fileDoc.ref.update({
      downloadCount: admin.firestore.FieldValue.increment(1),
    });
    
    return { url };
  });
```

**Expected result:** The Cloud Function verifies access, password, and expiry before returning a 15-minute signed download URL.

### 4. Build the download page with access verification UI

Create a DownloadPage that receives the fileId as a URL parameter. On Page Load, query the shared_files document to get the filename, size, and whether a password is required. Display the file info: filename, size formatted (KB/MB), and upload date. If the file requires a password, show a TextField for password entry and a Download button. If no password is needed, show the Download button directly. On button tap, call the getSecureDownloadUrl Cloud Function with the fileId and password. On success, launch the returned signed URL to start the download. On error, show the appropriate message (expired, no access, wrong password).

**Expected result:** The download page shows file info, requests a password if needed, and securely downloads the file.

### 5. Build the file management dashboard for file owners

Create a MySharedFiles page showing all files uploaded by the current user. Add a ListView bound to shared_files where uploaderId equals the current user's ID, ordered by createdAt descending. Each list item shows: filename, size, download count, expiry date (or 'No expiry'), and the number of people it is shared with. Add action buttons: Copy Link (copies the share URL to clipboard), Edit (modify sharedWith, password, or expiry), and Delete (removes both the Firestore document and the Storage file). This gives file owners full visibility and control over their shared files.

**Expected result:** File owners see all their shared files with download stats and can manage access, edit settings, or delete files.

## Complete code example

File: `FlutterFlow Secure File Sharing System`

```text
FIRESTORE SCHEMA:
  shared_files (collection):
    uploaderId: String
    filename: String
    storagePath: String (internal Storage path, never direct URL)
    size: int (bytes)
    mimeType: String
    sharedWith: [String] (userIds or 'public')
    password: String (SHA-256 hash, optional)
    expiresAt: Timestamp (optional)
    downloadCount: int (default 0)
    createdAt: Timestamp

FIREBASE STORAGE RULES:
  // Block all direct access — downloads go through Cloud Function
  match /shared/{allPaths=**} {
    allow read: if false;  // No direct reads
    allow write: if request.auth != null;  // Auth users can upload
  }

PAGE: UploadFile
  FlutterFlowUploadButton (documents, images, PDFs)
  Switch: Public / Private
  TextField: share with userIds (for private)
  Switch: Password protection + TextField (password)
  DateTimePicker: expiry date (optional)
  Button "Share" → create shared_files doc + generate link

CLOUD FUNCTION: getSecureDownloadUrl
  Input: fileId, password (optional)
  Checks: auth → sharedWith → password → expiresAt
  On pass: generate 15-min signed URL + increment downloadCount
  On fail: return specific error (expired/denied/wrong password)

PAGE: DownloadPage (URL param: fileId)
  On Load: fetch shared_files doc
  Display: filename, size, upload date
  If password required: TextField + Download button
  If no password: Download button directly
  On tap: call getSecureDownloadUrl → Launch URL

PAGE: MySharedFiles
  ListView: shared_files where uploaderId == currentUser
  Each item: filename + size + downloads + expiry
  Actions: Copy Link | Edit | Delete
```

## Common mistakes

- **Using permanent Firebase Storage download URLs for shared files** — Anyone who obtains the URL can download the file forever, even after you revoke access or the link expires. The URL bypasses all your Firestore-level access controls. Fix: Block direct Storage access with security rules. Route all downloads through a Cloud Function that generates short-lived signed URLs (15-minute expiry) after verifying permissions.
- **Storing passwords in plaintext in Firestore** — If anyone gains read access to your Firestore data (admin, security breach), all file passwords are immediately visible. Fix: Hash passwords with SHA-256 before storing. When verifying, hash the input password and compare hashes. Never store or transmit plaintext passwords.
- **Not checking the expiry date before generating the download URL** — Expired links still work because the Cloud Function does not validate the expiresAt field. Users share files with a 7-day expiry but the link works indefinitely. Fix: Always check if the current time is past expiresAt before generating the signed URL. Return a clear 'Link expired' error message.

## Best practices

- Route all downloads through Cloud Functions instead of using direct Storage URLs
- Use short-lived signed URLs (15 minutes) to minimize exposure window
- Hash passwords before storing them in Firestore
- Track download counts so file owners know how their files are being accessed
- Block direct Firebase Storage access with security rules that deny all reads
- Provide clear error messages for expired links, wrong passwords, and access denied
- Allow file owners to revoke access by removing userIds from the sharedWith array

## Frequently asked questions

### What file types can I support?

Firebase Storage supports any file type. Configure the FlutterFlowUploadButton's allowed types to match your needs: documents (pdf, docx), images (png, jpg), spreadsheets (xlsx, csv), or any combination. Set a maximum file size to prevent abuse.

### Can I share files with people who do not have an account?

Yes. Set the sharedWith array to include 'public' and optionally add a password. Anyone with the link and password can download without authentication. The Cloud Function skips the userId check for public files.

### How do I revoke access to a shared file?

Remove the user's ID from the sharedWith array or delete the shared_files document entirely. Since download URLs expire in 15 minutes, revoking access takes effect within that window at most.

### Is there a file size limit?

Firebase Storage supports files up to 5TB. However, FlutterFlowUploadButton has practical limits based on mobile network speeds. For large files, consider chunked uploads via a Custom Action.

### Can I add download notifications for file owners?

Yes. In the getSecureDownloadUrl Cloud Function, after incrementing downloadCount, create a notification document or send a push notification to the file owner with the downloader's name and timestamp.

### Can RapidDev help build secure file management systems?

Yes. RapidDev can build enterprise file sharing with encryption, audit logging, compliance controls, watermarking, and integration with document management platforms.

---

Source: https://www.rapidevelopers.com/flutterflow-tutorials/how-to-set-up-a-secure-file-sharing-system-in-flutterflow
© RapidDev — https://www.rapidevelopers.com/flutterflow-tutorials/how-to-set-up-a-secure-file-sharing-system-in-flutterflow
