React Native Meteor: OAuth with Facebook

This is a bit more advanced of a tutorial — if you’re going through this tutorial you should already be comfortable establishing a DDP connection from React Native to Meteor. In this example I’ll be using react-native-meteor, it’s still a work in progress but will work for our purposes in this tutorial. I’ll be skipping over configuration of that, if you need to follow the introduction here.

You can see all of this code here: https://github.com/spencercarli/react-native-meteor-accounts

Meteor

Before we get into anything else we’ll take care of the “easy” step — wiring Facebook OAuth in the browser. This will let us set up the project and get that out of the way so we can really focus on the React Native parts.

This has been written about multiple times so if you get stuck please refer to some of the various articles on this subject. My reference is this guide put together by The Meteor Chef. We’re covering it here again because it shows us that the code we’re writing for React Native will still work for the browser.

Once you’ve created your Meteor app you’ll want to add a few packages.

meteor add accounts-facebook service-configuration accounts-ui

Once that’s done create a settings.json file in your Meteor app directory. We’ll used that to store our Facebook info in a moment. To follow along with the following snippets use this code structure.

Creating the Facebook App

First, we want to create a new app at this link. For right now just start with creating for a website. We’ll add the platform dependent ones to our Facebook app later. Go ahead and skip the “quick start”.

That should drop you off here:

Go ahead and copy the “App ID” and place it in the appId field in settings.json. Do the same for “App Secret”. Okay, that should be done now.

Connecting Meteor

Now we need to hook up our app. I’m using Meteor 1.3 conventions in these code snippets. First on our server we’ll create server/imports/oauth-facebook.js with the following code

After we import the necessary code we’re grabbing our settings info. If the settings don’t exist then we’re not going to try to insert anything. If we’ve got the data though we’ll store that in the ServiceConfiguration collection. This will be used by accounts-facebook for Meteor and our code later.

Since this is 1.3 we’ve got to import our new code into the server entry file.

Last thing we’ll do on the Meteor side is setup our accounts-ui buttons

This should set up up with this wonderful UI

Okay, now onto the new stuff.

React Native

Let’s cover the general React Native stuff first. We’ll be leveraging React Native FBSDK, a wrapper around the iOS and Android SDK.

Also you’ll want to set up a React Native project. Here’s a super brief guide on a way to get started:

react-native init RNFacebookExample && cd RNFacebookExample

Then follow the directions here to install react-native-meteor. Then

mkdir app && cd app/ && touch index.js

As a temporary solution you can use this in app/index.js

Finally, change index.ios.js and index.android.js to

Okay, you should now be good to do platform specific stuff. Feel free to only do the platform you’re interested in — the other isn’t required.

Also, as a prerequisite to the platform code we’ll need to install the actual SDK.

react-native install --save react-native-fbsdk
react-native link react-native-fbsdk

React Native iOS Setup

First step we want to take is add iOS support to our Facebook app. First go to the list of your apps and choose the one you’re using to follow along.

Then click the “Settings” tab, that should drop you off at a screen like so:

Now at the bottom of this page you’ll want to click “Add Platform” and select iOS.

Now you’ve got to add your app’s Bundle ID and enable Single Sign On. You can get your Bundle ID from XCode in the “General” tab. Your Facebook configuration should look something like this now.

Save your changes and either leave this tab open or copy your Facebook App ID and App Name. If you get stuck please reference the Facebook docs here.

Okay, now to our app…

I’m replicating the docs created here so if you run into issues please reference those instructions (they may change over time).

Now we want to download the Facebook SDK for iOS (that link will bring you to Facebook’s developer site, it won’t download some random zip file). Once you’ve got that unzip it and open it in Finder.

Open your React Native app’s Xcode project (ios/APP_NAME.xcodeproj) and with that open you want to drage and drop the following files from the FacebookSDK to the Frameworks group in Xcode — Bolts.framework, FBSDKCoreKit.framework, FBSDKLoginKit.framework, FBSDKShareKit.framework. Make sure to choose Create groups for any added folders and selected Copy items into destination group’s folder.

Now we need to configure our Info.plist in a way that the Facebook SDK can read the necessary values. This is following along with the instructions here.

In XCode we need to open our Info.plist and open it as source code.

Then add the following snipped before </dict>. Sub out your-app-id and your-app-name with the appropriate values for your application.

<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLSchemes</key>
<array>
<string>fb{your-app-id}</string>
</array>
</dict>
</array>
<key>FacebookAppID</key>
<string>{your-app-id}</string>
<key>FacebookDisplayName</key>
<string>{your-app-name}</string>

iOS 9 Support

This part tripped me up so make sure to do it. iOS made some changes in iOS 9 so we need to whitelist a few Facebook apps (read more here). Much like above we have to add the following.

<key>LSApplicationQueriesSchemes</key>
<array>
<string>fbapi</string>
<string>fb-messenger-api</string>
<string>fbauth2</string>
<string>fbshareextension</string>
</array>
<key>NSPhotoLibraryUsageDescription</key>
<string>{human-readable reason for photo access}</string>

Is this taking as long to setup as it is to write? Geez…

iOS10 Support

It’s been brought to my attention by Benjamin Cherion that in iOS10 you need to enable Keychain Sharing in Xcode.

Now you need to add a few things to your AppDelegate.m — the import will go at the top, near the other imports and the rest at the end, but before the end

Should be set up now! Now is Android :)

React Native Android Setup

First thing we have to do is configure our Facebook app for Android. These steps are based off this documentation.

I’m not super familiar with Android so I’ll be going through the Quick Start guide. You can find that here (for android). We’ll be configuring the SDK in a moment so just skip ahead to the Add Facebook App ID section. You should see something like this:

With that let’s add our facebook app id. Make sure to use your app id.

Then we need to setup android/app/src/main/AndroidManifest.xml. We’re confirming that

<uses-permission android:name=”android.permission.INTERNET” />

is in the file and adding

<meta-data android:name=”com.facebook.sdk.ApplicationId” android:value=”@string/facebook_app_id”/>

Now we need to add info to Facebook (again in their Quick Start guide. This info is coming from the following line in AndroidManifest.xml

<manifest xmlns:android=”http://schemas.android.com/apk/res/android" package=”com.rnfacebookexample”>

Since we’re not in the app store we can skip over this warning

We then have to create a development key hash like so

keytool -exportcert -alias androiddebugkey -keystore ~/.android/debug.keystore | openssl sha1 -binary | openssl base64

Add your new hash in the field. Each development machine will need their own hash. Note: You’ll have to do the same for a release hash.


Okay, now that we’ve got that side setup let’s setup our app to actually handle this stuff.

We’ve got to handle various imports to our MainActivity.java file, I’ve just handled them all here. You can view more details in the packages docs.

The following instructions will only work if you’re on React Native version 0.29 or greater, if below make sure to check out the official docs for the old instructions.

In your MainApplication.java file we need to import a few files and then create an instance variable of type CallbackManager. Then, we need to override the onCreate method, and finally register the sdk package in getPackages.

Then in MainActivity.java you need to override the onActivityResult method.

You should now be setup on Android! Let’s get to setting up the UI now.

React Native UI

Now that all of the configuration is setup let’s make use of it! We’ll have 100% code reuse in this aspect of our app. Let’s create some separate views, just to make things more obvious in a little bit. Run these commands from within the RNFacebookExample/app directory.

touch SignIn.js SignOut.js

then in those files

then let’s update app/index.js to use our new components.

Okay let’s add a Facebook login button! This code will live in app/SignIn.js. First we’ll import the Facebook SDK, including the LoginButton component. This component will give us the design of the button for free and we just need to pass in a few props. This includes the permissions we’re asking for and what to do when login finishes and, if needed, what to do when logout finishes.

So what are we going to do with this? We’ll pass this along to our Meteor backend and either create a user, if one doesn’t already exist, or log that user in, if one does exist. We’ll tap into the standard Meteor accounts system for this.

First thing we need to do is setup a new login handler on the Meteor server. This code will take place in our Meteor app in server/imports/oauth-facebook.js.

A quick overview of what we’re doing: Following the ServiceConfiguration (which I covered earlier) we’re registering a new login handler for Meteor. This allows us to call Meteor.call(login, {facebook: data}); (where data is what we get back from the Facebook SDK. It then tries to fetch data about the user from Facebook — this serves two purposes. 1 it checks the validity of the access token that was passed to our application and 2 it grabs some information for us so that we can build out the profile for the user. Lastly it checks if that user already exists in the database, if so then we log them in and update their info otherwise we create a new user for them. The last thing we have to do when registering a login handler is return an object with the userId.

This code could likely/should live in a package. During this transition period for Meteor I thought I would post the source here so you can implement it however works for your application.

Now that the Meteor side of things is set up to accept our Facebook login. We’ll be writing our FB related logic in a separate file to keep things cleaner and abstract what we can. This taps into a fair amount of react-native-meteor internals but it’s functional-I’ll update this as new/better patterns emerge.

In short we’re setting up a function that we can pass as a callback to our LoginButton button component that, if login was successful, will log us into Meteor. It’s also exposing a function that we can call when our component mounts to try and log us in if we don’t have a Meteor resume token but we do have a Facebook access token.

Now lets wire all this up and be done here.

First thing we’ll want to do is import our loginWithTokens function from fb-login.js. What we want to do is attempt to log the user in with their Facebook access token as soon as we have a connection. Note: react-native-meteor already logs a user in behind the scenes this function is serving as a backup incase the resume tokens expired but the user is still logged in with Facebook.

Since written a new onLoginFinished function in fb-login.js we’ll delete the existing one in SignIn.js and import our new one. That’s really all the change we have to do here.

Finally, the user should be able to sign out! Let’s give them that ability. All we’re doing here is creating a touchable area and when that area is touched we call react-native-meteor’s logout method.

You should now be able to run your app on Android via react-native run-android and on iOS via npm run ios. Note: If you’re running on a device (or an Android emulator) you’ll have to change localhost in app/index.js to your machine’s IP address.

DONEZO.

You’ll noticed that it’s also got a logout with Facebook button. You should handle this however makes sense for your application — explore the Facebook React Native SDK for more info on that.

That was a beast to write. I hope you found it valuable. If so, please recommend this post, help others minimize the pain associated with setting this up!

Want to learn more about building apps with React Native + Meteor? Sign up for my email list and I’ll show you how.