OAuth with Facebook and Google for ReactNative using Passport.js
Includes: definition, usage, flow, setup 3rd Parties, Server & client code
What is OAuth? 🤔
- It stands for Open Authorization.
- It’s an approach to authenticate a user using 3rd party services like Facebook, Google, Github, LinkedIn…
When to use? 📈
- We no longer need to validate a login or sign up form with information that can be given to us by a third party.
- Use in order to modernize your app and not be limited to a simple username/password kind of login :)
Flow 🌊
I will use Google as the 3rd party in this case
- User presses
Login with Google
button on the client. - Server listens to that request, and redirects the user to Google’s 3rd party authentication form to grant permission for our app to access their information.
- Once permission is granted, the server and the 3rd party exchange the user’s profile between them. The server now has access to their
firstName
,lastName
,email
and more. - Upon successful exchange of info, the 3rd party will call a redirection URL thats pointing to the your server. It’s up to your server to decide what to do with the data.
Ex: store in the database, send back to the client, save in session…
Step 1: Set up 3rd party
In this tutorial, I will be setting both Facebook
and Google
as my 3rd party authentications.
Assumptions:
- For the purpose of the tutorial, I am going to be using
localhost
all along. But you should replacelocalhost
to the address you will be hosting your server at. - As well, I assume you have setup a client project using
ReactNative
and a server project usingNode.js
andExpress
.
Facebook setup 👤📘
- Go to https://developers.facebook.com/apps/ and select
Create App
- Name your app as you like.
- You might have to login in to your facebook to complete creation.
- Select the
Facebook Login
product
- Go to
Settings
, underValid OAuth Redirect URI's
you will have to enter your redirection URL that will get called as a callback when the information has been successfully exchanged betweenFacebook
(3rd party) and our server. (Step 4 in Flow)
I made the URL as descriptive as possible:
http://localhost:5000/user/login/facebook/callback
- Go to
Settings
(under Dashboard on the side menu)→Basic
Inside ofApp domains
addlocalhost
- Copy the
App ID
and theApp secret
, we will use them later. - Press
Save changes
in the bottom.
G⭕O⭕O⭕gle Setup
- Go to https://developers.facebook.com/apps/ and select
NEW PROJECT
- Name your app as you like.
- You might have to login in to your gmail account to complete creation.
- Search for
Goolge+ API
and enable it.
- Go back to the Dashboard, click on
Go to APIs overview
→ Credentials and press onADD CREDENTIALS
→OAuth Client ID
Note: You have to complete a consent form.
Just fill up the App Name
,User support email
and Developer contact information
email on the bottom.
- Now go back to the
Credentials
Tab, click again onCreate Credentials
andOAuth Client ID
Here is our redirection URL for Google:http://localhost:5000/user/login/google/callback
- You may change the name to your own liking.
- Press
Create
and copyYour Client ID
andYour Client Secret
, we will use them in the next step.
Step 2: Setup the Server
- Install the needed dependencies
npm i --save express cookie-session passport passport-facebook passport-google-oauth20
Passport is an authentication middleware for Node.js
.
It has over 500+ strategies including: Local Authentication
, Google+
, Facebook
, Twitter
, GitLab
, LinkedIn
…
- Create a
.env
file and store the copied values fromFacebook
andGoogle
earlier.
- Run
npm i --D dotenv
, its a dev dependency that allows to load all environment variables from a.env
file intoprocess.env
- Create
passportConfig.js
to define the configuration for each strategy
Let’s go over this file:
‣ the env
values are what we copied from Google’s and Facebook’s console when registering our project.
‣ The callbackURL
is what each of this 3rd parties will call when user’s info was successfully exchanged with our server.
‣ If you want to see the email as well as the returned information, you must mention it in the profileFields
for Facebook.
- Create
initPassport.js
to initialize the strategies by passing it thefacebook
andgoogle
config we created earlier.
Let’s go over this file:
‣ Both strategies accept the config object frompassportConfig.js
.
‣ Assume user has granted permission to share their profile. A callback returns:accessToken
: If we want to go back and access more info about the user we will be able to do that.refreshToken
: is used to refresh the accessToken
as its expiring after certain amount of timeprofile
: the information the users allowed to be shared with our server.done
: calling this will redirect the user to the callback URL we defined earlier.
‣formatFB
& formatGoogle
are helper methods that I created to format the return object to be the same for every strategy. I personally chose to only use the firstName
, lastName
and email
.
‣serializeUser
is used after successful authentication to persist the user in the session.deserializeUser
is used to retrieve user data from session.
- Lastly, we create our
index.js
which is the start point to the server app.
Let’s go over this file:
‣ We initialize passport by calling initPassport
and passing app
to it.
‣ We then define 4 routes:
‣user/login/facebook
& user/login/google
will call the passport strategies that will ask the user for permission to share data.
‣ user/login/facebook/callback
& user/login/google/callback
are the routes that will be called upon successful profile exchange by the 3rd party service and our server.
We will redirect the user back to the client app using a URL. To allow that URL to open our app, we must configure it both on IOS and Android.
‣ add email
to both facebook and google scope to have access to the user’s email.
Step 3: Setup Deep Linking
Deep links take users to the correct destination in your app from any online and offline channel including email, social media, referrals, QR codes, and more.
In this case, we use the deep linking mechanism to open our app on the login
page. The URL will contain some information about the user that we will use on the client side to login.
Just a little break down of the URL:
memcaps://login?/firstName=${req.user.firstName}/lastName=${req.user.lastName}
‣memcaps
→ is the name I chose to refer to my app.
‣login
→ is the route I chose to redirect the user to.
‣ firstName
,lastName
and email
are the parameters I chose to return from the user’s profile.
Note: I assume you have routing already setup on the client similar to this:
IOS
- Open the project in XCode → Info → scroll until
URL Types
- Change
urlSchemes
to the name you desire, I chosememcaps
and will be able to call the deep link like so:memcaps://…
- Open
AppDelegate.m
and add#import <React/RCTLinkingManager.h>
on the top
- Add this function to the bottom of the file:
‣ the return
part is what enables the deep linking on ios.
Android
- Add this code to
AndroidManifest.xml
‣ android:host="app"
and android:scheme="memcaps"
with the help of the intent is what allows us to reference our app from an outside source.
‣ Don’t forget to change android:name
to your own app name.
App
- Both platforms are setup. We must let our app know that we want to use deep linking.
Create a file calledlinking.js
and define your config
Notice how I reference the app with memcaps://app
which is what our ios
and android
are also configured to do.
In this particular config, I decided to only define the Login
path that parses the incoming params after the /
.
You can define a lot more screen if you need and you can call them by any name.
- Lastly, reference the
linking
file in the main Navigator of your app like so:
Step 4: Setup the Client
- Install this library on the client
npm install --save react-native-safari-view react-native-webview
Just some background:
For deep linking, we usually theLinking.openURL()
method.
Apple considers this as bad UX as this doesn't guarantee the user will use the default Safari browser on IOS. Hence why I use this library.
Otherwise, for android we will use react-native-webview
.
- Add 2 buttons like this in your login component
‣openUrl
is a method we will define soon that will call our backend which will trigger the 3rd party authorization form that will look something like this:
Google in this example:
- In the same Login component, add a
useEffect
function that listens to “incoming URL’s”.
Let’s go over this file:
‣useEffect
called when the component is about to load, we would want to check if this page was opened from a URL.
That is, we called memcaps://login...
to get here.
‣ we use WebView
for android but SafariView
for ios. SafariView.dismiss()
will get called when info is exchanged successfully and we want to close the browser to go back to the app.
The Webview
component doesn't have this kind of method, so we control it with simple useState
. That is, we set the URL to ''
when we want to close the browser and go back to the app.
Note that openURL
is the method that opens the browser in the first place.
‣ handleOpenURL
is a method that will accept the URL that looks somewhat like this:
memcaps://login?/firstName=Lara/lastName=Mo/email=laramo@gmail.com
this method will check if those params are defined.
If they are, we use the redux action login
to redirect the user to the home page.
And thats it!
Until next time,
Lara