Doorman + React Navigation

Customize your doorman navigation flow to work however you'd like.

Background

​React Navigation is an incredible library for managing navigation in React Native apps. This example shows how to integrate it with Doorman, for both v4 and v5.

​Doorman lets you add Firebase phone authentication to React Native and Expo apps with just a few lines of code. It provides a customizable UI, all the phone verification without a server, and you don't have to detach from Expo.

If you want to jump ahead, you can see the final code on Github (v5 code / v4 code).

What we're making

Let's recreate the quintessential Doorman auth flow, as seen in our welcome page.

Steps

  1. Create two custom screens

  2. Turn the two screens into a stack

  3. Add authentication functionality to our custom stack

Our example will have two files only: App.js and Stack.js. We'll start with Stack.js.

This guide assumes you've already gone through the installation steps for React Navigation.

1. Create two screens

Let's create our stack consisting of two screens – PhoneScreen and ConfirmScreen in a file called Stack.js.

React Navigation v5
React Navigation v4
React Navigation v5
// Stack.js
import React from 'react'
import { useNavigation } from '@react-navigation/native'
​
import { AuthFlow } from 'react-native-doorman'
​
const Phone = () => {
const { navigate } = useNavigation()
​
return (
<AuthFlow.PhoneScreen
onSmsSuccessfullySent={() => {
navigate('Confirm')
}}
renderHeader={null}
/>
)
}
​
const Confirm = () => (
<AuthFlow.ConfirmScreen
renderHeader={null}
/>
)
React Navigation v4
// Stack.js
import React from 'react'
import { useNavigation } from 'react-navigation-hooks'
​
import { AuthFlow } from 'react-native-doorman'
​
const Phone = () => {
const { navigate } = useNavigation()
​
return (
<AuthFlow.PhoneScreen
onSmsSuccessfullySent={() => {
navigate('Confirm')
}}
renderHeader={null}
/>
)
}
​
const Confirm = () => (
<AuthFlow.ConfirmScreen
renderHeader={null}
/>
)

All we did above was import the two pre-made screens from Doorman AuthFlow.ConfirmScreen & AuthFlow.PhoneScreen, and put them into their own components.

When an SMS is successfully sent, the onSmsSuccessfullySent function gets called. Here, we navigate to the confirm screen. In the next step, we'll add the actual navigation that lets us do that.

2. Turn our screens into a stack

Let's edit the Stack.js code to add a stack navigator.

We'll import createStackNavigator and export our new stack, like this:

React Navigation v5
React Navigation v4
React Navigation v5
// Stack.js
​
import { createStackNavigator } from '@react-navigation/stack'
​
// ... other code from step #1
​
​
const Stack = createStackNavigator()
​
const AuthStack = () => (
<Stack.Navigator>
<Stack.Screen name="Phone" component={Phone} />
<Stack.Screen name="Confirm" component={Confirm} />
</Stack.Navigator>
)
​
export default AuthStack
React Navigation v4
// Stack.js
​
import { createStackNavigator } from 'react-navigation-stack'
​
// ...other code from Stack.js (in step #1)
​
const AuthStack = createStackNavigator({
Phone,
Screen
})
​
export default AuthStack

This follows the example of the React Navigation Hello World.

Here is the final Stack.js file:

React Navigation v5
React Navigation v4
React Navigation v5
import React from 'react'
import { useNavigation } from '@react-navigation/native'
import { createStackNavigator } from '@react-navigation/stack'
​
import { AuthFlow } from 'react-native-doorman'
​
const Phone = () => {
const { navigate } = useNavigation()
​
return (
<AuthFlow.PhoneScreen
onSmsSuccessfullySent={() => {
navigate('Confirm')
}}
renderHeader={null}
/>
)
}
​
const Confirm = () => (
<AuthFlow.ConfirmScreen
renderHeader={null}
/>
)
​
const Stack = createStackNavigator()
​
const AuthStack = () => (
<Stack.Navigator>
<Stack.Screen name="Phone" component={Phone} />
<Stack.Screen name="Confirm" component={Confirm} />
</Stack.Navigator>
)
​
export default AuthStack
React Navigation v4
import React from 'react'
import { useNavigation } from 'react-navigation-hooks'
import { createStackNavigator } from 'react-navigation-stack'
​
import { AuthFlow } from 'react-native-doorman'
​
const Phone = () => {
const { navigate } = useNavigation()
​
return (
<AuthFlow.PhoneScreen
onSmsSuccessfullySent={() => {
navigate('Confirm')
}}
renderHeader={null}
/>
)
}
​
const Confirm = () => (
<AuthFlow.ConfirmScreen
renderHeader={null}
/>
)
​
const AuthStack = createStackNavigator({
Phone,
Screen
})
​
​
export default AuthStack

We now have a working React Navigation stack for our AuthFlow! How easy was that?

The final step is making these actually work with Doorman's phone authentication. We'll see that in step 3.

3. Add auth functionality

Let's start by creating a simple App.js file that initializes Firebase and adds React Navigation's app container.

React Navigation v5
React Navigation v4
React Navigation v5
// App.js
​
import * as React from 'react';
import { NavigationContainer } from '@react-navigation/native';
​
// initialize firebase
import firebase from 'firebase/app'
import 'firebase/auth'
firebase.initializeApp(YOUR_FIREBASE_CONFIG)
​
// create our App component, shown once we've authed
const AuthedApp = () => (
<Text
onPress={() => firebase.auth().signOut()}
style={{ paddingTop: 300, color: 'blue', fontSize: 24 }}
>
This app is authed!!
</Text>
)
​
const App = () => {
return (
<NavigationContainer>
</NavigationContainer>
);
}
​
export default App
React Navigation v4
// App.js
​
import * as React from 'react';
​
// initialize firebase
import firebase from 'firebase/app'
import 'firebase/auth'
firebase.initializeApp(YOUR_FIREBASE_CONFIG)
​
// create our App component, shown once we've authed
const AuthedApp = () => (
<Text
onPress={() => firebase.auth().signOut()}
style={{ paddingTop: 300, color: 'blue', fontSize: 24 }}
>
This app is authed!!
</Text>
)
​
const App = () => {
return (
<>
// we'll update this in the next step
</>
);
}
​
export default App

Replace YOUR_FIREBASE_CONFIG with your project's. How do I find my Firebase config?​

If you already have an app created (you probably do), then you can replace AuthedApp above with your App component.

3.1 Add Doorman to your app

The rest is the same as the original quick example, with one difference: you replace Doorman's AuthFlow component with your custom AuthStack from Stack.js.

React Navigation v5
React Navigation v4
React Navigation v5
// App.js
import * as React from 'react'
import { DoormanProvider, AuthGate } from 'react-native-doorman'
​
import AuthStack from './Stack'
​
// initialize firebase
import firebase from 'firebase/app'
import 'firebase/auth'
firebase.initializeApp(YOUR_FIREBASE_CONFIG)
​
// create our App component, shown once we've authed
const AuthedApp = () => (
<Text
onPress={() => firebase.auth().signOut()}
style={{ paddingTop: 300, color: 'blue', fontSize: 24 }}
>
This app is authed!!
</Text>
)
​
const App = () => {
return (
<NavigationContainer>
<DoormanProvider publicProjectId="YOUR-PROJECT-ID">
<AuthGate>
{({ user, loading }) => {
if (loading) return <></>
// if a user is authenticated
if (user) return <AuthedApp />
// otherwise, send them to the auth flow
return <AuthStack />
}}
</AuthGate>
</DoormanProvider>
</NavigationContainer>
);
}
​
export default App
React Navigation v4
// App.js
import { DoormanProvider, AuthGate } from 'react-native-doorman'
import { createAppContainer } from 'react-navigation'
​
import AuthStack from './Stack' // <-- made in step #2 πŸ˜‡
​
const Navigator = createAppContainer(AuthStack)
​
// initialize firebase
import firebase from 'firebase/app'
import 'firebase/auth'
firebase.initializeApp(YOUR_FIREBASE_CONFIG)
​
// create our App component, shown once we've authed
const AuthedApp = () => (
<Text
onPress={() => firebase.auth().signOut()}
style={{ paddingTop: 300, color: 'blue', fontSize: 24 }}
>
This app is authed!!
</Text>
)
​
const App = () => {
return (
<DoormanProvider publicProjectId="YOUR-PROJECT-ID">
<AuthGate>
{({ user, loading }) => {
if (loading) return <></>
// if a user is authenticated
if (user) return <AuthedApp />
// otherwise, send them to the auth flow
return <Navigator />
}}
</AuthGate>
</DoormanProvider>
);
}
​
export default App

Let's recap what we did above.

  1. Import the DoormanProvider and AuthGate components from react-native-doorman into your App.js, and place them inside the NavigationContainer.

  2. Place them within the NavigationContainer (if you're using v5.)

  3. Replace the DoormanProvider's publicProjectId prop with your own project ID.

  4. If there is a user, meaning Doorman has authenticated someone using Firebase auth, we render our AuthedApp component.

  5. Otherwise, we render our custom AuthStack flow from Stack.js.

Here's the final App.js:

React Navigation v5
React Navigation v4
React Navigation v5
// App.js
​
import * as React from 'react';
import { DoormanProvider, AuthGate } from 'react-native-doorman'
​
import AuthStack from './Stack' // <-- made in step #2 πŸ˜‡
​
// initialize firebase
import firebase from 'firebase/app'
import 'firebase/auth'
firebase.initializeApp(YOUR_FIREBASE_CONFIG)
​
// create our App component, shown once we've authed
// you can replace this with your App it exists
const AuthedApp = () => (
<Text
onPress={() => firebase.auth().signOut()}
style={{ paddingTop: 300, color: 'blue', fontSize: 24 }}
>
This app is authed!!
</Text>
)
const App = () => {
return (
<NavigationContainer>
<DoormanProvider publicProjectId="YOUR-PROJECT-ID">
<AuthGate>
{({ user, loading }) => {
if (loading) return <></>
// if a user is authenticated
if (user) return <AuthedApp />
// otherwise, send them to the auth flow
return <AuthStack />
}}
</AuthGate>
</DoormanProvider>
</NavigationContainer>
);
}
​
export default App
React Navigation v4
// App.js
​
import * as React from 'react';
import AuthStack from './Stack' // <-- made in step #2 πŸ˜‡
import { DoormanProvider, AuthGate } from 'react-native-doorman'
import { createAppContainer } from 'react-navigation'
​
// initialize firebase
import firebase from 'firebase/app'
import 'firebase/auth'
firebase.initializeApp(YOUR_FIREBASE_CONFIG)
​
// create react navigation container
const Navigator = createAppContainer(AuthStack)
​
// create our App component, shown once we've authed
// you can replace this with your App it exists
const AuthedApp = () => (
<Text
onPress={() => firebase.auth().signOut()}
style={{ paddingTop: 300, color: 'blue', fontSize: 24 }}
>
This app is authed!!
</Text>
)
​
const App = () => {
return (
<DoormanProvider publicProjectId="YOUR-PROJECT-ID">
<AuthGate>
{({ user, loading }) => {
if (loading) return <></>
// if a user is authenticated
if (user) return <AuthedApp />
// otherwise, send them to the auth flow
return <AuthStack />
}}
</AuthGate>
</DoormanProvider>
);
}
​
export default App

πŸ”₯Doorman added! Your React Native / Expo app now has Firebase phone auth, made custom with React Navigation.

Want to customize the styles of your screens? See docs for the AuthFlow.PhoneScreen and AuthFlow.ConfirmScreen.

Need help?

You can live chat with me (Fernando) at doorman.cool. Or try tweeting @FernandoTheRojo.