Secure React Native apps with Asgardeo

How to Integrate Asgardeo with your React Native Apps for a Seamless Auth Experience

Secure React Native apps with Asgardeo

Asgardeo is an IDaaS platform that helps organizations simplify and secure their IAM processes. It offers a wide range of features, including SSO, social login, MFA, passwordless authentication, user management, and logging, making it a great option for organizations looking to simplify and secure their IAM processes.

React Native is an open-source cross-platform mobile development framework created by Meta Platforms, Inc. It is used to develop applications for Android, iOS, macOS, tvOS, Web, Windows, and UWP by enabling developers to use the React framework along with native platform capabilities.

In this guide, we will explore how to integrate Asgardeo into your React Native apps, using react-native-app-auth, a well know authentication SDK for React Native apps.

· · ·

What are we going to build

We are going to build a super simple application that has login and logout capabilities. Our application will have two screens, one is public and the other one is private. Users will have to authenticate by proving their identity to access the private page. This protected page will also show the logged-in user's information.

· · ·

Create a new React Native project

The Official React Native Getting Started page contains the most up-todate information on how to setup the development environment and creating a new React Native project. Follow the steps outlined there, based on the operating system and your targeted mobile platform.

Once you are up and running with the new React Native project, come back to this guide to follow the next steps.

· · ·

Install dependencies

Stop the running metro server and run the following command in the project root to intall the required dependencies.

npm install react-native-app-auth rn-secure-storage react-navigation --save

As Asgardeo conforms to the standard identity management specifications, you can use any standard SDK/library that implements standard identity protocols to integrate Asgardeo with your applications. For this reason, we can use the standard react-native-app-auth package to add Asgardeo auth to our React Native application.

react-navigation is a navigation library for React Native, that allows you to easily navigate between screens in your app, with support for gestures, animations, and customizability. We will be using it to configure navigation in our mobile app.

After the sign-in is completed, we need to store the credentials received (eg: access token, id token, refresh token etc.) securely in the device itself. The rn-secure-storage package provides that secure storage capability utilizing the underlying platform specific secure storage features.

💡 Tip

If you are unable to use rn-secure-storage package, have a look at the other recommendations

· · ·

Create an Asgardeo application and a user

To integrate Asgardeo with our mobile app, we first need to create an application on Asgardeo console and obtain app-specific credentials. Follow the comprehensive guide in the Asgardeo documentation to create an application.

We also need to have a user in our organization to log into our app using Asgardeo. Create a user in your Asgardeo organization by following these steps.

Once you created an application and a user, come back to this guide to follow the next steps.

· · ·

Developing the app

To demonstrate the sign in with Asgardeo, we are building a simple app with two pages, home and dashboard. The home screen contains a button to initiate the sign in process, while the second screen has a Sign Out button. Let's first create the skeleton of two screens.

🗒️ Note

The styles and the imports have been excluded in some of the following code snippets for brevity.

· · ·

Creating the views

Create src/views/HomeScreen.tsx and add the following content.


  export const HomeScreen = () => {

    const signIn = () => {
      // we are going to update this function in the next steps.
    }

    return (
      <View>
        <TouchableOpacity onPress={signIn}>
          <Text>Sign In</Text>
        </TouchableOpacity>
      </View>
    )
  }
    

Create src/views/DashboardScreen.tsx and add the following content.


  export const DashboardScreen = () => {

    const signOut = () => {
      // we are going to update this function in the next steps.
    }

    return (
      <View>
        <TouchableOpacity onPress={signOut}>
          <Text>Sign Out</Text>
        </TouchableOpacity>
      </View>
    )
  }
  

We will be updating the signIn and signOut functions in the next steps.

· · ·

Creating context to hold authentication state

Let's use React Contexts to hold the user's authentication state in a way that's accessible by all views in our apps. Create a file src/contexts/UserContext.tsx and add the following code.


  import { createContext, Dispatch, SetStateAction } from 'react';

  export const UserContext = createContext<{
    isLoggedIn: boolean;
    setIsLoggedIn: Dispatch<SetStateAction<boolean>>;
  }>({
    isLoggedIn: false,
    setIsLoggedIn: (_isSignedIn: SetStateAction<boolean>) => null,
  });
  
· · ·

Configuring navigation

As the last step, let's define the navigation for these screens using the stack navigation available in react-navigation package.


import React, { useState } from 'react';
import { NavigationContainer } from '@react-navigation/native';
import { createNativeStackNavigator } from '@react-navigation/native-stack';
import { UserContext } from './src/contexts/UserContext';
import { DashboardScreen } from './src/views/Dashboard';
import { HomeScreen } from './src/views/Home';

function App(): JSX.Element {
  const [isLoggedIn, setIsLoggedIn] = useState(false);

  return (
    <UserContext.Provider value={{ isLoggedIn, setIsLoggedIn }}>
      <NavigationContainer>
        <Stack.Navigator initialRouteName="Home">
          {isLoggedIn ? (
            <Stack.Screen name="Dashboard" component={DashboardScreen} />
          ) : (
            <Stack.Screen
              name="Home"
              component={HomeScreen}
              options={{
                title: '',
                headerShown: false,
              }}
            />
          )}
        </Stack.Navigator>
      </NavigationContainer>
    </UserContext.Provider>
  );
}
  

Configuring Asgardeo

To integrate Asgardeo with our app, we need to specify some values that are unique to our Asgardeo organization. Create a file named src/config.ts and add the following. Make sure to update the placeholder values with your own values.

You can obtain these values from the Quick Start section of the application you created in the Asgardeo console.


export const config = {
    issuer: 'https://api.asgardeo.io/t/<your_org_name>/oauth2/token',
    clientId: '<your_application_id>',
    redirectUrl: 'myapp.auth://example',
    scopes: ['openid', 'profile'],
    postLogoutRedirectUrl: 'myapp.auth://example',
};
  

Here is a short description of each config value.

Config valueDescription
issuerAPI endpoint that issues tokens upon request.
clientIdThe Client ID of your OIDC app.
redirectUrlThe URL to which the app redirects to after user login.
scopesThe list of OIDC scopes that are used for requesting user information. The openid scope is mandatory to get the ID token. You can add other OIDC scopes such as profile and email.
postLogoutRedirectUrlThe URL which the app redirects to after user logout
· · ·

Add Login

We are using the authorize function provided by the authentication library to make the sign in work. Open the src/views/HomeScreen.tsx and update the signIn function as follows.

import { authorize } from 'react-native-app-auth';
import { config } from '../config';

const signIn = () => {
 try {
     setIsLoading(true);
     const result = await authorize(config);
 
     RNSecureStorage.set('authorizeResponse', JSON.stringify(result), {
       accessible: ACCESSIBLE.WHEN_UNLOCKED,
     }).then(
       _res => {
         setIsLoggedIn(true);
       },
       err => {
         throw err;
       },
     );
 } catch (error) {
     console.log(error);
     setIsLoggedIn(false);
 } finally {
     setIsLoading(false);
 }
}

Let's try to understand what's happening here.

In the very beginning of the signIn function, we update loading state variable to true so that the sign in button text is updated to Loading... until the browser is popped up. Then we call the authorize method from the react-native-app-auth library to handle the whole sign in process. The library then handles the authentication flow internally and eventually returns the authentication response.

An example authentication response would be as follows.

{
  "accessToken": "5da9101e-2572-3d8e-aeab-b6d8a114c324", 
  "accessTokenExpirationDate": "2023-07-30T13:42:56Z", 
  "authorizeAdditionalParameters": {
    "session_state": "e1dd600650d0aadbbae70604f1e8623b4f4244514be535246db9fa809554..."
  }, 
  "idToken": "eyJ4NXQiOiJaVGMxWW1Nd09HSmtPREE1WXprNFl6Z3dZbVpoWkRJNE1tUXpObU0xWVRjelpUS...", 
  "refreshToken": "6dcf5331-4aa6-3eda-9537-c9acf57962af", 
  "scopes": ["openid", "profile"], 
  "tokenAdditionalParameters": {}, 
  "tokenType": "Bearer"
}

Upon receiving the authentication response, we securely store it in the device for future use, and update the isLoggedIn state variable value to true, so that the private "Dashboard" screen is now visible.

· · ·

Add Logout

Now we have added the sign in capability, let's continue to work on sign out functionality. Update the signOut function in views/Dashboard.tsx as follows.

const signOut = async () => {
    if (!authResponse?.idToken) {
      setIsLoggedIn(false);
      return;
    }

    try {
      await logout(config, {
        idToken: authResponse?.idToken,
        postLogoutRedirectUrl: config.postLogoutRedirectUrl,
      });

      RNSecureStorage.remove('authorizeResponse')
        .then(_val => {
          setIsLoggedIn(false);
        })
        .catch(err => {
          throw err;
        });
    } catch (err) {
      console.log(err);
    }
};
  

Upon clicking on the sign out button, we remove the user credentials from device storage and redirect the user to the home screen.

· · ·

Wrapping Up

In this tutorial, we looked into integrating Asgardeo with your React Native application, using the standard react-native-app-auth package. I hope you found this guide useful. In case you faced any errors and have suggestions to improve the guide, please don't hesitate to open an issue in the demo repository.

Until the next time, Thanks for reading!!!



© Pavindu Lakshan | 2024