Firebase

PreviousNext

A React Native starter with BNA UI components and a Firebase backend — Cloud Firestore, Cloud Storage, Authentication and security rules with tests, with or without sign-in.

Firebase is Google's app platform: a document database that streams changes to every listener, object storage, an authentication service with a dozen providers, and a rules language that runs on Google's servers rather than in your app.

BNA UI ships two Firebase scaffolds: one with a backend and no sign-in, one with authentication and the screens already built. Both use the firebase JS SDK, so they run in Expo Go — no config plugin, no google-services.json, no development build to get started.

The auth starter

Built around the same principles as the rest of BNA UI:

  • Open Code: the authentication screens, the hooks and the security rules are copied into your project, not imported from a package.
  • Mobile-First: flows designed for React Native, with the persisted user encrypted in the platform keychain.
  • Cross-Platform: iOS, Android and web, from one code path.
  • Secure by default: every document scoped to request.auth.uid, enforced by Google — not by what the client asks for.

Sign-in methods

MethodMechanismShips with a screenExpo Go
Email + passwordsignInWithEmailAndPasswordYesYes
Password resetsendPasswordResetEmailYesYes
Email verificationsendEmailVerificationCard in SettingsYes
Googleexpo-auth-sessionsignInWithCredentialYesNo
Appleexpo-apple-authenticationsignInWithCredentialYesNo
Email linksendSignInLinkToEmailYes, hidden by defaultNo

What lands in your project

lib/
├── firebase.ts             the client — app, auth, Firestore, Storage
├── large-secure-store.ts   AES-256 persistence for the auth record
├── documents.ts            snapshot → plain object, as pure functions
├── auth-link.ts            the action-link parser, as a pure function
└── errors.ts               Firebase error code → prose
providers/auth-provider.tsx user, profile, deep links
app/(auth)/                 five screens
app/(onboarding)/           intro carousel + profile setup
firestore.rules             owner-only, with no catch-all match
storage.rules               avatars/<uid>/… and files/<uid>/…
rules-tests/                the rules, executed against the emulator

The two layers of access control

The route guards in app/_layout.tsx decide what renders:

app/_layout.tsx
<Stack.Protected guard={!signedIn}>
  <Stack.Screen name='(auth)' />
</Stack.Protected>
<Stack.Protected guard={signedIn && !needsOnboarding}>
  <Stack.Screen name='(tabs)' />
</Stack.Protected>

The security rules decide what Firestore will actually return:

match /tasks/{taskId} {
  allow read: if isOwner(resource.data.ownerId);
}

Only the second is a security boundary. The first is there so users are not looking at empty screens.

The rule that catches everyone

Firestore evaluates a read rule against the query, not against the documents it would return. It refuses any query it cannot prove in advance is limited to documents the rule allows:

// permission-denied, even signed in
query(collection(db, 'tasks'), orderBy('createdAt', 'desc'));
 
// fine
query(collection(db, 'tasks'), where('ownerId', '==', uid));

A Postgres RLS policy does the opposite: the filter is optional and the policy quietly narrows the result. If you are moving between the Supabase and Firebase starters, this is the difference that will bite you. Security rules covers it properly.

Reading the signed-in user

import { useAuth } from '@/providers/auth-provider';
 
const { user, profile, loading, signOut } = useAuth();

profile is the users/{uid} document, kept current over an onSnapshot subscription. user is the Firebase User record. There is no session — Firebase has no session object.

Environment

VariableWhere it livesSet byUsed for
EXPO_PUBLIC_FIREBASE_API_KEY.env.localbna-ui firebaseBuilding the client
EXPO_PUBLIC_FIREBASE_PROJECT_ID.env.localbna-ui firebaseBuilding the client
EXPO_PUBLIC_FIREBASE_APP_ID.env.localbna-ui firebaseBuilding the client
EXPO_PUBLIC_GOOGLE_*_CLIENT_ID.env.localYouGoogle sign-in
EXPO_PUBLIC_FIREBASE_LINK_URL.env.localYouEmail links
GOOGLE_APPLICATION_CREDENTIALSCIYouDeploying rules

Provider credentials — the Apple team key, SMTP settings, OAuth secrets — live in the Firebase console, not in any file in your repository.

Guides

Learn more