React Native and Firebase auth patterns I use in every mobile app I ship
Every React Native app I have shipped this year started the same way. New Expo project, a couple of screens, a Firebase project, and then a week of yak shaving on auth. Last year I got tired of writing the same auth module from scratch and consolidated the patterns I trust. They have now shipped in both Connect Us and Remart and I will reuse them on the next one.
The stack
- Expo SDK 54 as the runtime.
- Firebase Auth for email and password sign in, password reset, email verification.
- Firestore for the profile document and any role flags.
- AsyncStorage for persistence of the last known auth state, so the app does not flash a sign in screen on cold start when the user is already signed in.
- React Navigation with a guard at the navigator root that swaps between the auth stack and the app stack.
The auth context
The single rule that has saved me the most pain: there is exactly one place in the app that subscribes to Firebase auth state, and exactly one place that fetches the user profile. Everything else reads from a context.
useEffect(() => {
const unsub = onAuthStateChanged(auth, async (user) => {
if (!user) {
setState({ status: 'signed-out' })
return
}
const profile = await fetchProfile(user.uid)
setState({ status: 'signed-in', user, profile })
})
return unsub
}, [])Three states: loading, signed-out, signed-in. The navigator switches stacks based on the status. The status is the only thing the rest of the app needs to know.
Cold start without a flash
The annoying default of Firebase Auth is that the SDK takes a beat to restore the session on launch. If you render the sign in screen during that beat, the user sees a flash before getting kicked back to the app.
The fix is to render a splash screen until the first onAuthStateChanged callback fires. AsyncStorage stores a tiny flag from the previous session, the splash uses it to decide whether to look "signed in styled" or "signed out styled" while the SDK warms up. The flash goes away.
Profile state without race conditions
The classic bug is updating a profile document, then having the local state out of sync with Firestore for a moment. The fix is to write to Firestore, then write to local state from the snapshot listener, not from the form value. The listener is your source of truth. Optimistic UI is fine, but commit it through the listener path.
Deep links and password reset
This is the part nobody covers in tutorials. Password reset emails from Firebase open in a browser by default and the user has no way to get back to the app. The pattern that works:
- Configure a custom action URL in Firebase that points to your app's universal link domain.
- Handle the action code in the app via
Linking.addEventListener. - Verify the code with
verifyPasswordResetCode, then callconfirmPasswordResetwith the new password.
The same pattern handles email verification. Get it right once and you reuse it forever.
Push notifications and FCM
For Connect Us and Remart I use Expo notifications for the device side and Firebase Cloud Messaging on the server side. The pattern: every sign in, the app gets a push token and writes it to the user's profile document under pushTokens. On sign out you clear it. Server side, you fan out to whatever tokens you find on the profile. Multiple devices per user works for free.
What I would tell hiring managers
A clean auth module is a leading indicator of how the rest of the app is written. If a candidate's React Native repo has auth state scattered across three files, the rest of the app will be too. If the auth context is a single source of truth, the rest of the app probably is.
I am currently open to remote Senior and Staff mobile or cross platform roles. If your team is building anything that ships on iOS, Android, and web, I would love to talk.
Md. Tausif Hossain leads engineering at DevTechGuru and ships mobile apps independently as TechnicalBind. He is open to remote Senior and Staff roles. Reach him at tausif1337.dev.
Newsletter
Get new posts in your inbox.
Honest essays on engineering, leadership, and the things I’m figuring out. No spam, ever.