Search code examples
react-nativefacebook-graph-apiaccess-tokenexpo

How to get FB Access Token with Expo


I'm building app where i need to make Facebook Graph API requests in many places. But i dont know how to retrieve access token and then make Graph API request.

I'm using Expo, React Native and Firebase. I would like to do it without installing Xcode and/or Android Studio.

Login is working fine. My code is below:

async loginWithFacebook() {
try {
  const {
    type,
    token,
    expires,
    permissions,
    declinedPermissions,
  } = await Expo.Facebook.logInWithReadPermissionsAsync('<APP_ID', {
    permissions: ['email', 'public_profile'],
  });
  if (type === 'success') {
    const credential = f.auth.FacebookAuthProvider.credential(token)
    f.auth().signInAndRetrieveDataWithCredential(credential).catch((error) => {
      console.log(error)
    })
    var that = this;
    const response = await fetch(`https://graph.facebook.com/me/?fields=id,name&access_token=${token}`);
    const userInfo = await response.json();
    this.setState({userInfo});
    this.setState({
    dataSource: userInfo.data,
    isLoading: false,
    });
  } else {
    // type === 'cancel'
  }
} catch ({ message }) {
  alert(`Facebook Login Error: ${message}`);
}
}

Can someone help me and give me some tips how i can use access token everywhere in my app? Thank you in advance


Solution

  • Getting the token and saving it into AsyncStorage

    Well the code that you have written is basically correct. You have successfully got the access token. It comes back to you when you make the Expo.Facebook.logInWithReadPermissionsAsync request. Once you have it you could then store it in Redux or AsyncStorage to be used at a later date.

    logIn = async () => {
      let appID = '123456789012345' // <- you'll need to add your own appID here
    
      try {
        const {
          type,
          token, // <- this is your access token
          expires,
          permissions,
          declinedPermissions,
        } = await Expo.Facebook.logInWithReadPermissionsAsync(appID, { permissions: ['public_profile', 'email'], });
    
        if (type === 'success') {
          // Get the user's name using Facebook's Graph API
          const response = await fetch(`https://graph.facebook.com/me/?fields=id,name&access_token=${token}`); //<- use the token you got in your request
          const userInfo = await response.json();
          alert(userInfo.name);
    
          // you could now save the token in AsyncStorage, Redux or leave it in state
          await AsyncStorage.setItem('token', token); // <- save the token in AsyncStorage for later use
        } else {
          // type === 'cancel'
        }
    
      } catch ({ message }) {
        alert(`Facebook Login Error: ${message}`);
      }
    }
    

    app.json

    Also remember to add the following to your app.json, obviously replacing the values with your own. You get these by registering your app with Facebook, you can see more about that here https://docs.expo.io/versions/latest/sdk/facebook/#registering-your-app-with-facebook

    { 
      "expo": {
        "facebookScheme": "fb123456789012345",
        "facebookAppId": "123456789012345",  // <- this is the same appID that you require above when making your initial request. 
        "facebookDisplayName": "you_re_facebook_app_name",
        ...
        }
    }
    

    Getting token from AsyncStorage

    Then if you wanted to make another request at a later time you could have a function similar to this where you get the token out of AsyncStorage and then use it to make your request.

    makeGraphRequest = async () => {
      try {
        let token = await AsyncStorage.getItem('token'); // <- get the token from AsyncStorage
        const response = await fetch(`https://graph.facebook.com/me/?fields=id,name&access_token=${token}`); // <- use the token for making the graphQL request
        const userInfo = await response.json();
        alert(userInfo.name)
      } catch (err) {
        alert(err.message)
      }
    }
    

    Snack

    I would make a snack to show you this working however, snacks do not allow editing of the app.json file (as far as I can tell). So here is something that you could replace your App.js with and then if you added your appIDs etc to the app.json it should work.

    import React from 'react';
    import { AsyncStorage, Text, View, StyleSheet, SafeAreaView, Button } from 'react-native';
    
    
    export default class App extends React.Component {
    
      logIn = async () => {
        let appID = '123456789012345' // <- you'll need to add your own appID here
        try {
          const {
            type,
            token, // <- this is your access token
            expires,
            permissions,
            declinedPermissions,
          } = await Expo.Facebook.logInWithReadPermissionsAsync(appID, {
            permissions: ['public_profile', 'email'],
          });
          if (type === 'success') {
            // Get the user's name using Facebook's Graph API
            const response = await fetch(`https://graph.facebook.com/me/?fields=id,name&access_token=${token}`); //<- use the token you got in your request
            const userInfo = await response.json();
            console.log(userInfo);
            alert(userInfo.name);
            // you could now save the token in AsyncStorage, Redux or leave it in state
            await AsyncStorage.setItem('token', token); // <- save the token in AsyncStorage for later use
          } else {
            // type === 'cancel'
          }
        } catch ({ message }) {
          alert(`Facebook Login Error: ${message}`);
        }
      }
    
        makeGraphRequest = async () => {
          try {
            let token = await AsyncStorage.getItem('token');
            // Get the user's name using Facebook's Graph API
            const response = await fetch(`https://graph.facebook.com/me/?fields=id,name&access_token=${token}`);
            const userInfo = await response.json();
            alert(userInfo.name)
          } catch (err) {
            alert(err.message)
          }
        }
    
    
      render() {
        return (
          <View style={styles.container}>
            <Button title={'Sign in to Facebook'} onPress={this.logIn} />
            <Button  title={'Make GraphQL Request'} onPress={this.makeGraphRequest} />
          </View>
        )
      }
    }
    
    const styles = StyleSheet.create({
      container: {
        flex: 1,
        justifyContent: 'center',
        alignItems: 'center',
        backgroundColor: 'white'
      }
    });