To secure a Bolt.new + React + Firebase stack, you need to: (1) replace test-mode Firestore rules with production rules that verify authentication, (2) implement proper AuthContext with onAuthStateChanged for session persistence, (3) create protected route components to guard authenticated pages, and (4) ensure Firestore rules back up any UI-level restrictions since client-side protection alone is insufficient. This blueprint covers multi-layer security across the React and Firebase stack.
TL;DR
Bolt generates React + Firebase apps with common security gaps: test-mode Firestore rules, inconsistent auth state handling, and unprotected routes. After export: replace permissive security rules, implement proper auth context with onAuthStateChanged, add protected route components, and verify that UI-level protection is backed by Firestore rules.
React + Firebase Security Layers
This stack requires security at multiple levels:
| Layer | Purpose | Bolt Issues |
|---|---|---|
| Firestore Rules | Data access control | Often test mode or missing |
| React Auth Context | App-wide auth state | May not persist properly |
| Protected Routes | UX-level access control | Sometimes incomplete |
Part 1: Firestore Security Rules
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /users/{userId} {
allow read, update, delete: if request.auth != null
&& request.auth.uid == userId;
allow create: if request.auth != null;
}
match /items/{itemId} {
allow read, update, delete: if request.auth != null
&& resource.data.userId == request.auth.uid;
allow create: if request.auth != null
&& request.resource.data.userId == request.auth.uid;
}
}
}
Part 2: React Auth Context
import { createContext, useContext, useEffect, useState } from 'react';
import { onAuthStateChanged, User } from 'firebase/auth';
import { auth } from '../lib/firebase';
const AuthContext = createContext<{ user: User | null; loading: boolean }>({
user: null,
loading: true,
});
export function AuthProvider({ children }) {
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);
Remember: Protected routes are for UX only. Your Firestore rules are the real security layer.
Security Checklist
Post-Export Checklist for Bolt + React + Firebase
Firestore rules replaced from test mode
Storage rules configured (if using)
AuthContext implemented with onAuthStateChanged
Protected routes wrap authenticated pages
Data queries scoped to current user
Firebase config in environment variables
Alternative Stacks to Consider
**Bolt.new + Firebase**
General Firebase security guide
**Bolt.new + Next.js + Supabase**
Server-side rendering alternative
**Bolt.new + Convex**
Real-time TypeScript alternative
My protected routes work but data still leaks. Why?
React route protection only affects the UI. If your Firestore rules allow access, anyone can query your database directly. Always secure data at the Firestore rules level.