To secure a Cursor + React + Firebase stack, you need to: (1) replace test-mode Firestore rules with production rules that check authentication and ownership, (2) configure Firebase Storage rules to restrict file access, (3) use React Context to manage auth state consistently across components, (4) understand that client-side route protection is for UX only - Firestore rules are the real security, and (5) create a .cursorignore file to prevent AI from accessing environment files. This blueprint covers Firestore rules, React auth patterns, and the security boundary between client and server.
TL;DR
React + Firebase is a popular stack for rapid prototyping, but AI-generated code often ships with insecure defaults. Key issues: test-mode Firestore rules that allow public access, Firebase config exposed without proper security rules, and missing auth state checks in protected components. Always configure security rules before deploying, use React Context for auth state, and never trust client-side route protection alone.
Platform Guides & Checklists
Cursor Security Guide
React Security Guide
Firebase Security Guide
Pre-Launch Checklist
Stack Security Overview
This stack relies heavily on client-side code, which means security rules in Firebase are your primary defense:
| Component | Security Role | Common AI Mistakes |
|---|---|---|
| Cursor | Code generation | Generates permissive rules, skips auth checks |
| React | UI layer | Client-only route guards, exposed state |
| Firebase | Backend + Auth | Test mode rules, missing validation |
Part 1: Firestore Security Rules Firebase
The AI-Generated Problem Cursor Firebase
Cursor often generates code that works with test-mode rules:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read, write: if true; // Anyone can do anything!
}
}
}
Secure Rules Pattern Firebase
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
// User profiles - only owner can read/write
match /users/{userId} {
allow read, update, delete: if request.auth != null
&& request.auth.uid == userId;
allow create: if request.auth != null;
}
// Posts - public read, authenticated create, owner modify
match /posts/{postId} {
allow read: if true;
allow create: if request.auth != null
&& request.resource.data.authorId == request.auth.uid;
allow update, delete: if request.auth != null
&& resource.data.authorId == request.auth.uid;
}
// Private collections - strict user isolation
match /private/{userId}/{document=**} {
allow read, write: if request.auth != null
&& request.auth.uid == userId;
}
}
}
Part 2: React Auth Context React Firebase
Proper Auth State Management React
AI-generated React code often checks auth inconsistently. Use a centralized context:
import { createContext, useContext, useEffect, useState } from 'react';
import { onAuthStateChanged, User } from 'firebase/auth';
import { auth } from '../lib/firebase';
interface AuthContextType {
user: User | null;
loading: boolean;
}
const AuthContext = createContext<AuthContextType>({
user: null,
loading: true
});
export function AuthProvider({ children }: { children: React.ReactNode }) {
const [user, setUser] = useState<User | null>(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
const unsubscribe = onAuthStateChanged(auth, (user) => {
setUser(user);
setLoading(false);
});
return unsubscribe;
}, []);
return (
<AuthContext.Provider value={{ user, loading }}>
{children}
</AuthContext.Provider>
);
}
export const useAuth = () => useContext(AuthContext);
Protected Route Component React
import { Navigate } from 'react-router-dom';
import { useAuth } from '../contexts/AuthContext';
export function ProtectedRoute({ children }: { children: React.ReactNode }) {
const { user, loading } = useAuth();
if (loading) {
return <div>Loading...</div>;
}
if (!user) {
return <Navigate to="/login" replace />;
}
return <>{children}</>;
}
Remember: Client-side route protection is for UX only. Your Firestore security rules are the actual security barrier. Even with protected routes, malicious users can call Firebase directly.
Part 3: Firebase Configuration Firebase
Environment Variables React
# These are safe to expose (security comes from rules)
REACT_APP_FIREBASE_API_KEY=AIza...
REACT_APP_FIREBASE_AUTH_DOMAIN=yourapp.firebaseapp.com
REACT_APP_FIREBASE_PROJECT_ID=yourapp
REACT_APP_FIREBASE_STORAGE_BUCKET=yourapp.appspot.com
REACT_APP_FIREBASE_MESSAGING_SENDER_ID=123456789
REACT_APP_FIREBASE_APP_ID=1:123456789:web:abc123
import { initializeApp } from 'firebase/app';
import { getAuth } from 'firebase/auth';
import { getFirestore } from 'firebase/firestore';
const firebaseConfig = {
apiKey: process.env.REACT_APP_FIREBASE_API_KEY,
authDomain: process.env.REACT_APP_FIREBASE_AUTH_DOMAIN,
projectId: process.env.REACT_APP_FIREBASE_PROJECT_ID,
storageBucket: process.env.REACT_APP_FIREBASE_STORAGE_BUCKET,
messagingSenderId: process.env.REACT_APP_FIREBASE_MESSAGING_SENDER_ID,
appId: process.env.REACT_APP_FIREBASE_APP_ID,
};
const app = initializeApp(firebaseConfig);
export const auth = getAuth(app);
export const db = getFirestore(app);
Security Checklist
Pre-Launch Checklist for Cursor + React + Firebase
Firestore rules updated from test mode
Storage rules configured (if using)
Auth context provides consistent state
Protected routes use auth context
Firebase config uses environment variables
.cursorignore excludes .env files
Rules tested with Firebase Emulator
Auth domain configured for production URL
Alternative Stack Configurations
Cursor + Firebase + Vercel Same Firebase security with Vercel hosting. Adds server-side capabilities with API routes.
Cursor + Supabase + Vercel
Swap Firebase for Supabase. Different security model with PostgreSQL RLS instead of Firestore rules.
Bolt.new + React + Firebase
Same React + Firebase stack with Bolt.new. Different AI code generation approach.
Is it safe to expose Firebase config in React?
Yes, the Firebase client config (apiKey, authDomain, etc.) is designed for public exposure. Your security comes from Firestore and Storage rules, not from hiding these values. The apiKey identifies your project but doesn't grant access.
Why do I need both route protection and Firestore rules?
Route protection improves UX by redirecting unauthenticated users. But React runs on the client, so users can bypass it. Firestore rules run on Firebase's servers and are the actual security enforcement.
How do I test my security rules?
Use the Firebase Emulator Suite locally or the Rules Playground in Firebase Console. Write test cases for authenticated users, unauthenticated users, and users trying to access other users' data.
Building React + Firebase with Cursor?
Scan your app for security rule issues and auth problems.
Start Free Scan