Facebook Login/Auth CRNA Expo

Is there a way to implement logging into facebook without having to input facebook user name and password?

I found this: https://github.com/magus/react-native-facebook-login. I’m using CRNA (create-react-native-app) with Expo and from what I understand I’d have to eject the project in order to use react-native-facebook-login because there is native code in that component.

I’d like to mimic the behavior that react-native-facebook-login provides. Is that possible using expo?

Does this do what you need?

As far as I am aware of, no.

It’s what I’m using now but the pop-up requires a user to login with their username (email/phone number) and password. The behavior I’m looking for is for the user not to have to enter that info as demo’d here: https://github.com/magus/react-native-facebook-login

Facebook.logInWithReadPermissionsAsync('<APP ID>', { permissions: ['public_profile', 'email', 'user_friends', 'user_photos']});

If you mean you want to read whatever Facebook authorization already exists on the device, the only way to do that on Expo iOS right now is to use the WebBrowser module (which shares cookies with Safari). cc @notbrent

Sorry, I’m a newbie. Do you have any more info about this? Maybe a link?

Here’s an example you might find useful: https://github.com/expo/examples/tree/master/with-facebook-auth

Thanks. I opened it (https://github.com/expo/examples/tree/master/with-facebook-auth) in the expo app but it looks like this example also prompts the user to log in Facebook with username and password but the only difference is that I think it’s via web view rather than the Expo style popup.

What I’m hoping to integrate is for the user to be able to log into an app via FB without having to input their Facebook details (username/email/phone number and password). Just basically exactly like this: GitHub - magus/react-native-facebook-login: React Native component wrapping the native Facebook SDK login button and manager but I believe I can’t use this module because it uses native code and I would have to eject the project from Expo.

Hi @hiromih! the example in with-facebook-auth shows how to use SFSafariViewController on iOS and Chrome Custom Tabs on Android via the Expo WebBrowser module. These underlying APIs share cookies with Safari / Chrome, so if the user has ever logged into Facebook with their device’s web browser then they will not need to enter a username / password. This is by far the most common way to do OAuth on mobile apps these days.

If you would like to use the Facebook app itself (not recommended), you can follow the steps in the documentation, in particular you will need to use native behavior on iOS and system on Android. This is a pain because it works differently in the Expo client and in standalone apps, and requires a lot of configuration.

1 Like

@notbrent - Just wanted to say thanks for the very helpful explanation and the example you provided (https://github.com/expo/examples/tree/master/with-facebook-auth).

I thought I might share my experience making it work in the Expo client & a standalone app since this seems like something many other Expo users may be interested in.

I noticed in your example, you have two deployments of the backend server (e.g. local expo app, and published expo app). I ended up doing a hack where I passed the redirect link to my small express server because there’s several different types of redirects you might want to do:

A) expo on real phone: (e.g. exp://qq-7gt.username.yarn.exp.direct/+)
B) expo on simulator: (e.g. exp://localhost:19000/+)
C) standalone app (e.g. customApp://…)

Even within expo, the ports might change or subdomain identifier, so it seems cumbersome to have to re-deploy a small express app for each unique path.

This is the relevant snippet I used for normalizing across these cases:

const linkingUrl = Expo.Constants.appOwnership === 'expo' ? Expo.Constants.linkingUri.match(/\w+:\/\/[\w-.]+:?\d*/)[0] : 'customAppScheme:/';

It’s a hairy RegEx and I used / abused the state parameter (which is intended for CSRF) to have Facebook pass the linkingUrl:

const FacebookAuthURI = `https://www.facebook.com/v2.9/dialog/oauth?client_id=${AppID}&redirect_uri=${redirectUrl}&state=${linkingUrl}`;

It seems sketchy to me (security-wise) so I’m going to whitelist certain linkingUrl on the server-side.

It feels very hacky but it works and it’s such a nice UX flow. What do you think? I can’t think of a better way without actually detaching from Expo and using the official FB RN SDK.

How to you setup the redirect url? On iOS, my app can ask permissions but once they are given, I get invalid redirect url on ios, with this as the safari url: Log into Facebook | Facebook

Can you help me?

Have you taken a look at the example: https://github.com/expo/examples/tree/master/with-facebook-auth?

You need to setup a small server to redirect to your exp app because Facebook doesn’t allow you to directly redirect to a custom scheme. You can use now.sh or Firebase Functions to deploy this server.

Please visit this page regarding react native facebook login : android - You are not logged in. Please log in and try again - Stack Overflow

Source: Travel App Development

I made a Firebase Function, but what URL do you need to put for the redirect for my standalone app? I saw in the app.json configuration that i can create a scheme for the redirect, but where can I find the actual URL to redirect to my from from my function?

@wwwillchen will you be able to share the working code with us?

Here’s a quick consolidation of the Facebook + Instagram (non-graph api auth) code I’ve used. I added a quick conditional only to show that this code can be used for either Social Login. The _openWebBrowserAsync() is essentially from wth-webbrowser-redirect example.

const isProduction = appOwnership === 'standalone';
const responseType = 'token';
const redirectUrl = isProduction
  ? Linking.makeUrl('/login')
  : AuthSession.getRedirectUrl();
const socialUrl = socialType === 'facebook' 
  ? 'https://www.facebook.com/v3.2/dialog/oauth?'
  : `https://api.instagram.com/oauth/authorize/?`;
const authUrl = `${socialUrl}`
  + `client_id=${clientId}`
  + `&redirect_uri=${encodeURIComponent(redirectUrl)}`
  + `&response_type=${responseType}`;
const result = isProduction
  ? await this._openWebBrowserAsync(authUrl)
  : await AuthSession.startAsync({ authUrl });

if (['cancel', 'dismissed', 'error', 'locked'].includes(result.type)) {
  /*
    type:
      - 'cancel': process manually interrupted by user through closing browser
      - 'dismissed': process manually interrupted by us (AuthSession.dismiss())
      - 'error': {type: 'error', params: Object, errorCode: string, event: Object }
      - 'locked': an AuthSession was attempted while another was active

      if type='cancel', then there's a chance they wanted the business authentication,
      and this is where the prompt screen could be applied.
   */

  // eslint-disable-next-line
  console.error('[LoginScreen] onLoginWithSocial FAIL. result: ', JSON.stringify(result, null, 2));

  return;
}

// result will be of format: { type: 'success', params: Object, event: Object }
const socialToken = result.params.access_token;