

Authentication is an important concern when building apps. A common use case we come across when building apps is securing our API in order to accept only authenticated requests, hence preventing misuse.
In this story, Iβll be using a Todos app built with React Native and explain how to create a secure Node/Express API to handle the Create, Update and Delete operations for the app. This will let the app only allow editing of data by authenticated users. For this post weβll assume that:
The key components that I will be using for the app are:
You can check out a screencast of the appΒ here.
ReactiveSearch is an open-source React and React Native UI components library for Elasticsearch which Iβve co-authored with some awesome people. It provides a variety of React Native components that can connect to any Elasticsearch cluster.
In this story Iβll be expanding on another story I wrote on How to build a real-time todo app with React Native which you may check out if youβre interested in building the starter project which Iβll be using here.
We will use the Todos app built with appbase.io and ReactiveSearch Native as a baseline to build our authenticated Todos app. Iβve already setup starter projects which weβll use both for client and server side. However, before we dive into the code, Iβll talk about a few concepts.
{
"title": "Writing code",
"completed": true,
"createdAt": 1518766646430,
"name": "divyanshu",
"avatar": "https://s.gravatar.com/avatar/33ca46e56260bc7d54b2d7246f9a7052?s=480&r=pg&d=https%3A%2F%2Fcdn.auth0.com%2Favatars%2Fdi.png"
}
Before we start building the UI, weβll need a place to store our todos. For brevity, you can use my app which is hosted on appbase.io or clone it for yourself by following this link and clicking on Clone this App button. This will let you make a copy of the dataset as your own app.
Weβre using Auth0 for handling authentication which uses JWT (JSON Web Tokens) as the access tokens. It comprises three parts header, payload and signature separated by dots(.). A JWT looks like:
xxx.yyy.zzz
The header(xxx) defines the type of token and the algorithm used for hashing. The payload(yyy) contains information about the user and additional metadata. The signature(zzz) is used to verify the sender of the token and ensure the message was not tampered along the way. You can find a more detailed explanation at the JWT introduction guide.
Another popular alternative to using JWT tokens has been managing sessions. However, that introduces statefulnessβββJWT, being stateless, is a better approach.
The access token once verified tells us that the user is authorized to access the API and forms the basis of our token based authentication system. The authentication flow will look as follows:
The final directory structure will look something like this:
android // android related configs
ios // ios related configs
components
βββ RootComponent.js // Root component for our app
βββ MainTabNavigator.js // Tab navigation component
βββ TodosScreen.js // Renders the TodosContainer
βββ Header.js // Header component
βββ AddTodo.js // Add todo input
βββ AddTodoButton.js // Add todo floating button
βββ TodoItem.js // The todo item
βββ TodosContainer.js // Todos main container
api
βββ todos.js // APIs for performing writes
constants // Some constants used in the app
types // Todo type to be used with prop-types
utils // Streaming logic goes here
Here are the final repositories so you can refer to them at anytime:
(i) Todos Auth Client (React Native App)
(ii) Todos Auth Server (Node/Express server)
We are starting with the Todos app code from this previous post and adding an authentication flow to it. You can use the following repositories as starter project files:
(i) Todos Native Auth Client starter project
(ii) Todos Native Auth Server starter project
After youβve cloned the projects you can switch into the client project directory and test it out:
npm install
npm start
react-native run-ios (or)
react-native run-android
This will start the Todos app (which has the entire logic on client side). Now that everything is up and running, we can start writing the authentication flow code.
Note
Weβre using an ejected create-react-native-app template, hence the reason for usingreact-native
for running the app. This is needed by thereact-native-auth0
package which Iβm using here for authentication purposes.
Auth0 requires the callbacks for ios
or android
which you can define in the following manner:
{PRODUCT_BUNDLE_IDENTIFIER}://divyanshu.auth0.com/ios/{PRODUCT_BUNDLE_IDENTIFIER}/callback
and
{YOUR_APP_PACKAGE_NAME}://divyanshu.auth0.com/android/{YOUR_APP_PACKAGE_NAME}/callback
You can add these to your applicationβs callback URL via the Auth0 dashboard.
For our case the package name is com.todosnative
however you can use your own package name and update the same in android manifest and ios plist files. In the starter files Iβve already added these but if you were to do them by yourself, this is how you may done it (here you can skip to the next step):
AndroidManifest.xml
file at /android/app/src/main/AndroidManifest.xml
package="com.auth0sample"
Info.plist
file at /ios/todosnative/Info.plist
<key>CFBundleIdentifier</key>
<string>com.todosnative</string>
The dependency for react-native-auth0
is already present in the starter project. You can run the following command to link
all the native dependencies:
react-native link
Next, we can update the AndroidManifest.xml
file to have a launchMode
of singleTask
and add another intent-filter
Β . The file should look something like:
<activity
android:name=".MainActivity"
android:label="@string/app_name"
android:launchMode="singleTask" android:configChanges="keyboard|keyboardHidden|orientation|screenSize"
android:windowSoftInputMode="adjustResize">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data
android:host="YOUR_AUTH0_DOMAIN"
android:pathPrefix="/android/YOUR_APPLICATION_ID/callback"
android:scheme="YOUR_APPLICATION_ID" />
</intent-filter>
</activity>
You can substitute the stub values with your own auth0 domain and application id.
Next, update the /ios/todosnative/AppDelegate.m
file and add the following:
#import <React/RCTLinkingManager.h>
/* Add the following after @implementation AppDelegate */
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url
sourceApplication:(NSString *)sourceApplication annotation:(id)annotation
{
return [RCTLinkingManager application:application openURL:url
sourceApplication:sourceApplication annotation:annotation];
}
Next, weβll add a CFBundleURLSchemes
in the Info.plist
file:
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleTypeRole</key>
<string>None</string>
<key>CFBundleURLName</key>
<string>auth0</string>
<key>CFBundleURLSchemes</key>
<array>
<string>org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)</string>
</array>
</dict>
</array>
When you start the app from the starter project, it will look something like the following:
Note that initially you will not be able to add, delete or update the todo items. Weβll add the methods to handle these operations shortly.
First lets add the login Button
in /components/TodosContainer.js
. You may add the following in the render
function of TodosContainer
Β :
<ScrollView>
<Button
title="Login Button"
style={{
marginTop: 10,
marginBottom: 10
}}
/>
...
Next, weβll create handlers for login and logout in /components/RootComponent.js
and pass them to the child components for use. Iβve added comments in the starter project to identify where we would need to add code.
For authentication, Iβm using react-native-auth0. You can use your own Auth0 domain
and clientId
here. In the handleLogin
method weβre saving the accessToken
along with user avatar
and name
in state. The handleLogout
method will remove these from the state. All the handlers and state are passed via screenProps
to the child components rendered by the MainTabNavigator
component which uses TabNavigator
from react-navigation
. It takes these props and makes them available under screenProps
.
Weβll use these in /components/TodosContainer.js
:
Now weβll be able to login by clicking on the login button and save the access token for use.
After the authentication happens, Iβm saving the accessToken
, avatar
and name
in the state of /components/RootComponent
. These are made available to the children components via screenProps
by the TabNavigator
in /components/MainTabNavigator.js
. In the previous step, we already passed the screenProps
to the TodoItem
component. Next, weβll update the component to make them pass to the API calls.
So far, we have just console logged when invoking the add
, update
or delete
calls. Next, Iβll be using three endpoints to handle writes on the data:
Hereβs how we can handle these calls on the client side app. Weβll add these to /api/todos.js
:
One thing youβll notice here is Iβm passing some headers
in the fetch
calls. Iβm using the access token we received earlier and passing it in all the calls. Weβll use this to verify the requests on the server side. The body
includes the necessary data for creating, updating or deleting the todos. Also, the calls will not go through if the access token is not present.
Now, for the final missing piece, hereβs how Iβm handling the requests on the server:
Here the checkJwt
middleware verifies the access token on each request using the same audience
which we specified on the client side and your domain
specified here as the issuer
. If the token is absent or invalid the request will be rejected as unauthorized. Now you can fire up the server in a different terminal and youβll be able to handle writes for your app securely. π
Hope you enjoyed this story. You might also like some related stories Iβve written:
Create your free account to unlock your custom reading experience.