Skip to main content
RapidDev - Software Development Agency
flutterflow-tutorials

How Can I Troubleshoot Common FlutterFlow Security Problems

Debug FlutterFlow security issues systematically: use the Firebase Rules Monitor to diagnose permission denied errors, rotate exposed API keys immediately, fix App Check rejections by adding your app's debug token for development, resolve CORS errors on Cloud Functions by adding origin headers, and force token refresh for stale auth sessions. Never fix permission denied by setting Firestore rules to allow read, write.

What you'll learn

  • Use the Firebase Rules Monitor to pinpoint exactly which Firestore rule is denying access
  • Rotate an exposed API key and audit where else it may have been used
  • Resolve Firebase App Check rejections without disabling App Check
  • Fix CORS errors on Cloud Functions and diagnose stale authentication tokens
Book a free consultation
4.9Clutch rating
600+Happy partners
17+Countries served
190+Team members
Beginner12 min read30-40 minFlutterFlow Free+March 2026RapidDev Engineering Team
TL;DR

Debug FlutterFlow security issues systematically: use the Firebase Rules Monitor to diagnose permission denied errors, rotate exposed API keys immediately, fix App Check rejections by adding your app's debug token for development, resolve CORS errors on Cloud Functions by adding origin headers, and force token refresh for stale auth sessions. Never fix permission denied by setting Firestore rules to allow read, write.

Security Bugs Are Different From Regular Bugs — Here Is How to Debug Them

Regular app bugs produce visible errors in the UI. Security bugs often fail silently — data just does not appear, an action does nothing, or a page stays blank. This makes them harder to debug than a crash. The most dangerous debugging instinct is to remove all security rules to confirm the app works, then add rules back later. That pattern is how production apps end up permanently open. This tutorial teaches systematic security debugging for FlutterFlow: use the right Firebase tools to find the exact failure point, fix it minimally and precisely, and verify the fix without compromising other security boundaries.

Prerequisites

  • FlutterFlow project connected to Firebase with Firestore and Authentication
  • Access to the Firebase console (Firestore, Authentication, and Functions tabs)
  • Basic understanding of Firestore Security Rules syntax
  • Firebase CLI installed locally for testing Security Rules with the emulator (optional but helpful)

Step-by-step guide

1

Diagnose permission denied errors using the Firestore Rules Monitor

When a Firestore read or write fails silently in FlutterFlow, the first tool to use is the Firebase console's Rules Monitor. Go to Firestore > Rules > Monitor rules. Enable monitoring and reproduce the failing action in your app. The Monitor shows every rules evaluation in real time — the request path, the requesting UID, and whether the rule allowed or denied the request. Find the denied request and look at the `allow` condition that failed. Most permission denied errors fall into three categories: (1) the user is not authenticated (`request.auth == null`), (2) the UID does not match the document's `ownerId` field, or (3) a new collection was added to the app but no rule was written for it yet. Fix the specific rule that failed — do not broaden all rules to compensate.

Expected result: You identify the exact rule condition that is failing. The fix is a targeted change to one rule, not a blanket allow.

2

Identify and fix data visible to the wrong users

If users can see each other's data — another user's profile, private documents, or payment history — the most common cause is Firestore rules using `allow read: if true` or a missing ownership check. In the Firebase console, go to Firestore > Rules and search for any rule that contains `if true` or `allow read;` without a condition. Replace these with explicit conditions. For user-owned data, the correct pattern is `allow read: if request.auth != null && request.auth.uid == resource.data.ownerId`. Also check list (collection-level) queries — a document-level rule that passes does not protect against a query that returns all documents in the collection. Add query constraints in your Firestore Security Rules to validate query filters match the authenticated user.

firestore.rules
1rules_version = '2';
2service cloud.firestore {
3 match /databases/{database}/documents {
4
5 // WRONG — allows anyone to read any user document
6 // match /users/{userId} {
7 // allow read: if true;
8 // }
9
10 // CORRECT — user can only read their own document
11 match /users/{userId} {
12 allow read, write: if request.auth != null
13 && request.auth.uid == userId;
14 }
15
16 // CORRECT — user can only query their own documents
17 match /orders/{orderId} {
18 allow read: if request.auth != null
19 && resource.data.userId == request.auth.uid;
20
21 // Validate query constraints match authenticated user
22 allow list: if request.auth != null
23 && request.query.filters['userId'] == request.auth.uid;
24 }
25 }
26}

Expected result: Querying for another user's documents returns an empty result or a permission denied error rather than their private data.

3

Rotate an exposed API key and audit damage

If you have accidentally committed an API key to GitHub, embedded it in a FlutterFlow API Manager header visible in the app binary, or shared it in a screenshot, treat it as compromised immediately. For Firebase API keys: go to the Google Cloud console > APIs and Services > Credentials, find the exposed key, and click Edit to restrict it by IP, referrer, or app bundle ID. Firebase web API keys cannot be fully secret (they are embedded in Firebase config), so the real protection is Firebase Security Rules and App Check — not key secrecy. For third-party API keys (Stripe, OpenAI): go to that provider's dashboard and revoke the exposed key, create a new key, and store the new key as a Firebase Function Secret. Move the API call from FlutterFlow API Manager to a Cloud Function.

Expected result: The old key is revoked. The new key is stored only in Firebase Function Secrets. No API calls are made directly from FlutterFlow to the third-party service.

4

Resolve Firebase App Check rejecting legitimate requests

Firebase App Check verifies that requests to Firebase services come from your legitimate app, not scripts or bots. When enabled, it can reject requests from legitimate sources in two common cases: (1) during FlutterFlow development, the preview runs in a browser environment that does not have your app's debug attestation token, and (2) after updating your app's bundle ID or SHA certificate fingerprint without updating App Check. For development, go to the Firebase console > App Check > Apps, find your app, and click Add debug token. Copy the debug token and add it to your FlutterFlow app's App Check configuration. For production issues, ensure your iOS app's App Attest key ID and Android app's Play Integrity API are correctly configured in App Check settings.

Expected result: FlutterFlow preview and development builds can access Firebase services while App Check remains enabled for production.

5

Fix CORS errors on Cloud Functions called from FlutterFlow

Cross-Origin Resource Sharing (CORS) errors appear when your FlutterFlow web app calls a Cloud Function that does not include the correct `Access-Control-Allow-Origin` response header. In the Cloud Function, install the `cors` npm package and wrap your HTTP function handler. For callable functions (`onCall`), Firebase handles CORS automatically — you only need to add CORS headers for HTTP functions (`onRequest`). If you are seeing CORS errors on a callable function, the issue is usually not CORS — it is an authentication error or function not found. Check the browser console for the actual error message behind the CORS error.

functions/cors_example.js
1// For onRequest HTTP functions that need CORS
2const { onRequest } = require('firebase-functions/v2/https');
3const cors = require('cors')({ origin: true });
4
5exports.myHttpFunction = onRequest((req, res) => {
6 cors(req, res, () => {
7 // Handle request after CORS headers are set
8 if (req.method === 'OPTIONS') {
9 res.status(204).send('');
10 return;
11 }
12 res.json({ message: 'Hello' });
13 });
14});
15
16// onCall functions handle CORS automatically — no cors package needed
17// If you see a CORS error on onCall, check:
18// 1. Is the function deployed? (test with firebase functions:list)
19// 2. Is the user authenticated? (onCall returns 401 without auth)
20// 3. Is the function name spelled correctly in FlutterFlow?

Expected result: Cloud Function calls from the FlutterFlow web preview and deployed web app succeed without CORS errors.

6

Fix stale authentication tokens causing intermittent permission errors

Firebase ID tokens expire after one hour. In a long-running FlutterFlow session, an expired token causes Firestore reads and Cloud Function calls to fail with permission denied or unauthenticated errors. FlutterFlow's Firebase integration automatically refreshes tokens in the background for most cases, but issues can occur on mobile after the app is backgrounded for a long time. In FlutterFlow, add an action on the App Foreground event (Settings > App Settings > On App Foreground) that calls a Custom Action to force-refresh the Firebase ID token: `await FirebaseAuth.instance.currentUser?.getIdToken(true)`. The `true` parameter forces a refresh even if the current token is not yet expired. Also check that your Cloud Functions are not caching old auth tokens — if you pass the token as a header manually, refresh it before each request.

custom_actions/refresh_auth_token.dart
1// Custom Action: refreshAuthToken
2import 'package:firebase_auth/firebase_auth.dart';
3
4Future refreshAuthToken() async {
5 final user = FirebaseAuth.instance.currentUser;
6 if (user != null) {
7 await user.getIdToken(true); // force = true refreshes immediately
8 }
9}

Expected result: Users who return to the app after several hours no longer experience permission denied errors on their first action.

Complete working example

firestore.rules
1rules_version = '2';
2service cloud.firestore {
3 match /databases/{database}/documents {
4
5 // Helper functions
6 function isSignedIn() {
7 return request.auth != null;
8 }
9
10 function isOwner(ownerId) {
11 return isSignedIn() && request.auth.uid == ownerId;
12 }
13
14 function isAdmin() {
15 return isSignedIn() &&
16 get(/databases/$(database)/documents/users/$(request.auth.uid)).data.role == 'admin';
17 }
18
19 // Users can only read/write their own user document
20 match /users/{userId} {
21 allow read: if isSignedIn() && request.auth.uid == userId;
22 allow create: if isSignedIn() && request.auth.uid == userId;
23 allow update: if isOwner(userId);
24 allow delete: if false; // Never allow user deletion from client
25 }
26
27 // Orders: user can read their own, admin can read all
28 match /orders/{orderId} {
29 allow read: if isOwner(resource.data.userId) || isAdmin();
30 allow create: if isSignedIn()
31 && request.resource.data.userId == request.auth.uid;
32 allow update: if isAdmin();
33 allow delete: if false;
34 }
35
36 // Shared documents: owner or explicitly shared users
37 match /documents/{docId} {
38 allow read: if isSignedIn() && (
39 resource.data.ownerId == request.auth.uid ||
40 request.auth.uid in resource.data.sharedWith
41 );
42 allow write: if isOwner(resource.data.ownerId);
43 }
44
45 // Deny everything else explicitly
46 match /{document=**} {
47 allow read, write: if false;
48 }
49 }
50}

Common mistakes

Why it's a problem: Fixing permission denied errors by changing Firestore rules to `allow read, write: if true`

How to avoid: Use the Firebase Rules Monitor to find the specific rule that is failing. Fix only that rule with the minimum necessary permissions. Use the Rules Playground to verify the fix works before deploying.

Why it's a problem: Seeing a CORS error and assuming it is a CORS configuration problem on the Cloud Function

How to avoid: Open the browser DevTools Network tab and look at the actual request and response, not just the CORS error in the Console. A 404 on the function URL means it is not deployed. A 401 means authentication is failing. Only a 200 preflight response with missing Access-Control headers is a true CORS error.

Why it's a problem: Disabling Firebase App Check to fix development errors rather than adding a debug token

How to avoid: Keep App Check enabled. For development environments, add a debug token in the Firebase console under App Check > Apps > Add debug token. Use this token only for development — never embed it in production builds.

Best practices

  • Use the Firebase Rules Monitor and Playground before changing any rules — understand the exact failure before writing a fix.
  • Never set Firestore rules to `allow read, write: if true`, even temporarily during debugging — use a test user account with the proper UID instead.
  • Add an explicit deny-all rule at the bottom of your Firestore rules: `match /{document=**} { allow read, write: if false; }` — this catches any collections not yet covered by specific rules.
  • Store all third-party API keys as Firebase Function Secrets — rotate any key that has appeared in source code, environment variables in the client, or screenshots.
  • Add a token refresh call on app foreground to prevent stale auth tokens from causing intermittent permission errors after long background sessions.
  • Test Security Rules changes using the Firebase Emulator locally before deploying to production — `firebase emulators:start` runs a local rules evaluator.
  • Enable Firebase App Check in production and use debug tokens for development — do not disable it to fix development errors.

Still stuck?

Copy one of these prompts to get a personalized, step-by-step explanation.

ChatGPT Prompt

My FlutterFlow app uses Firestore and I am getting permission denied errors when users try to read their own profile documents. I have a `users` collection where each document is keyed by the user's Firebase UID and has an `ownerId` field equal to the UID. My current rules are `allow read: if request.auth != null && resource.data.ownerId == request.auth.uid`. The error occurs even when the user is signed in. What are all the possible reasons this rule could fail and how do I debug each one using the Firebase Rules Monitor and Playground?

FlutterFlow Prompt

My FlutterFlow app calls Firebase Cloud Functions and works fine on mobile but I get CORS errors when testing on the web in the FlutterFlow preview. The functions are `onCall` callable functions, not HTTP functions. I am not setting any custom CORS headers. What are the most likely causes of CORS errors on Firebase callable functions and how do I diagnose the real underlying error?

Frequently asked questions

How do I know if my Firestore rules are too permissive?

In the Firebase Rules Playground, try to read or write a document as a different user than the one who owns it. If the Playground allows the request, your rules are too permissive. Also check for any rule containing `if true` or no condition at all — these grant unrestricted access. Run the Firebase Security Rules audit tool at security.rules.firebase.google.com for automated suggestions.

My users are getting signed out randomly. What causes this?

The most common causes are: (1) token refresh failing because the device is offline when the token expires, (2) the user's account being disabled or deleted in Firebase Authentication, or (3) calling `FirebaseAuth.instance.signOut()` accidentally in an error handler. Check your FlutterFlow auth routing — the 'Entry Page' setting should handle unauthenticated sessions gracefully rather than signing users out.

How do I test Firestore Security Rules without deploying them?

Use the Firebase Local Emulator. Run `firebase emulators:start` which starts a local Firestore emulator with rules evaluation. Point your FlutterFlow app to the emulator by setting the Firestore emulator host in your app's Firebase initialization. The emulator shows rule evaluation details in its UI. You can also use the Rules Playground in the Firebase console to test rules against simulated requests without affecting production.

What is the difference between a Firebase API key and a service account key?

A Firebase API key (the web config key starting with `AIza...`) is designed to be public-facing — it identifies your project and can be safely included in client-side code. Its access is controlled by Firebase Security Rules and App Check. A service account key (a JSON file with a private key) grants admin-level access bypassing all Security Rules. Service account keys must never be included in client apps or committed to GitHub — use them only in Cloud Functions running on Google Cloud infrastructure.

Why does my Cloud Function return 401 even when the user is signed in?

Callable Cloud Functions receive the auth context automatically if the Firebase SDK is initialized correctly in the client. Common causes of 401 on callable functions: (1) the function is being called before the user completes sign-in, (2) the Firebase SDK is not initialized with the same project as the function, or (3) App Check is enabled and the debug token is not configured. Log `request.auth` at the start of the function to see what authentication context the function actually receives.

Should I use Firebase App Check or Firestore Security Rules — or both?

Both, for different threats. App Check verifies that requests come from your legitimate app binary — it blocks bots, scripts, and other apps from calling your Firebase services. Firestore Security Rules verify that the authenticated user is allowed to read or write a specific document — they enforce data access control. App Check does not replace Security Rules, and Security Rules do not replace App Check. Enable both in production.

RapidDev

Talk to an Expert

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

Book a free consultation

Need help with your project?

Our experts have built 600+ apps and can accelerate your development. Book a free consultation — no strings attached.

Book a free consultation

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.