1. Prepare React Native Development Environment

https://docs.expo.dev/get-started/installation/

In this guide, we will proceed with React Native development using Expo.

Please follow the React Native development environment setup according to the official Expo documentation linked above. If you already have a React Native development environment set up, you can proceed to the next steps.

Download Git Repository

If you want to use a sample project, download the following Git repository:

Download the Furo Expo Sample project.

git clone https://github.com/lukasjhan/furo-sample-expo

If you want to create your own project, please follow the guide below.

Library Installation and Usage

In this guide, we will use the following libraries:

npm i @react-navigation/native @react-navigation/native-stack
npm i axios
// package.json
"dependencies": {
    "@react-navigation/native": "^6.1.7",
    "@react-navigation/native-stack": "^6.9.13",
    "axios": "^1.4.0",
    //...
}
  • @react-navigation/native, @react-navigation/native-stack

    These libraries are used for deep linking after login.

  • axios

    This library is used for Furo’s authentication API.

//App.js

import { NavigationContainer } from '@react-navigation/native';
import { createNativeStackNavigator } from '@react-navigation/native-stack';

export default function App() {
  const linking = {
    prefixes: ['exp://'],
    config: {
      screens: {
        Home: '*',
      },
    };
    const Stack = createNativeStackNavigator();

    return (
      <NavigationContainer linking={linking}>
        <Stack.Navigator>
          <Stack.Screen name="Home" component={HomeScreen} />
        </Stack.Navigator>
      </NavigationContainer>
    );
  }
}

To retrieve deep link params in the future, add a linking config in App.js and include NavigationContainer and Stack in the top-level component.

2. Integrate Furo Login

  1. Copy .env value to .env file in project directory. Or, create a .env file and set the environment variables as follows. If you cannot use the .env file, enter the Client ID obtained from the console in clientId of the App.js file.
EXPO_PUBLIC_CLIENT_ID="{{YOUR_CLIENT_ID}}"
  1. Change the Default Callback URI in the console’s input box from the default value https://sample.furo.one/{{YOUR_CLIENT_ID}} to http://localhost:3000/{{YOUR_CLIENT_ID}}.

3. Sample Code

import * as React from 'react';
import { StatusBar } from 'expo-status-bar';
import { StyleSheet, Text, View, Button, Linking } from 'react-native';
import { NavigationContainer } from '@react-navigation/native';
import { createNativeStackNavigator } from '@react-navigation/native-stack';
import axios from 'axios';

const CLIENT_ID = ''; // Insert your Furo project's client id

export default function App() {
  const linking = {
    prefixes: ['exp://'],
    config: {
      screens: {
        Home: '*',
      },
    };
    const Stack = createNativeStackNavigator();

    return (
      <NavigationContainer linking={linking}>
        <Stack.Navigator>
          <Stack.Screen name="Home" component={HomeScreen} />
        </Stack.Navigator>
      </NavigationContainer>
    );
  }
}

function HomeScreen({ route }) {
  const [data, setData] = React.useState();

  React.useEffect(() => {
    Linking.addEventListener('url', ({ url }) => {
      const query = url.split('?');
      if (query.length < 2) return;
      const [, code] = query[1].split('=');
      if (code) {
        (async () => {
          try {
            const response = await authenticateWithCode(code);
            const { access_token } = response;
            setData(access_token);
          } catch (e) {
            console.log('error: ', e.response.data);
          }
        })();
      }
    });
  }, []);
  const loginUrl = `https://auth.furo.one/login/${CLIENT_ID}`;

  const loginWithRedirect = async () => {
    Linking.openURL(loginUrl);
  };

  const authenticateWithCode = async (code) => {
    const { data } = await axios.post(
      'https://api.furo.one/sessions/code/authenticate',
      { code },
      { headers: { origin: 'exp://' } }
    );
    return data;
  };

  return (
    <View style={styles.container}>
      <Text style={{ fontSize: 16, fontWeight: '600' }}>
        [Furo] React Native Tutorial
      </Text>
      <View style={{ marginTop: 10, width: '80%' }}>
        <Text>{data}</Text>
      </View>
      <StatusBar style="auto" />
      {!data ? (
        <Button title={'Sign In'} onPress={loginWithRedirect} />
      ) : (
        <Button title={'Clear'} onPress={() => setData()} />
      )}
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#fff',
    alignItems: 'center',
    justifyContent: 'center',
  },
});

Please insert your Furo project’s Client ID in the CLIENT_ID variable and follow the instructions to set up Furo login in your React Native application.