DEV Community

Cover image for React Context API login example using FaceIO for face authentication.
John Thiong'o
John Thiong'o

Posted on

React Context API login example using FaceIO for face authentication.

Hi there,

In this build I am going to show the use of the React Context API and the useReduce hook to manage state in a react application. To demonstrate this we will build a user authentication react component, taking advantage of the simple FaceIO face authentication system to authenticate our users. Once they are authenticated we will then pass the user data to the state and be able to consume it in other components.

Why we will use FaceIO.

FaceIO is a facial authentication system for websites and web based applications.

FaceIO is,

  1. Very easy to implement. It takes less than 3 lines of code and basically entails adding a script like the google gtag. For more you can check here.
  2. Seamless and does not entail the user getting FIDO keys, OTP codes and security questions thereby enhancing user experience in our site.
  3. Very secure. First it provides a defense level facial recognition accuracy ensuring that we accurately authenticate each and every user using their facial recognition engine. Secondly it guarantees the privacy of the user by ensuring that there data is safe and also that they don’t actually store the face of the user but rather a facial vector.

This is part two of a two part series if you would like to follow along part one is here.

We are going to pick up from where we left last time. Firstly we are going to arrange our content appropriately

In the src folder let us create a folder pages and in it create two files named Home.tsx and SignUp.tsx

Next we are going to add react router dom

So that your build should now look like this,

fileStructure

We are going to transfer all the contents of App.tsx to the home page except the SignUpForm.

const Home = () => {
  return (
    <div className='min-h-screen flex flex-col '>
      <h1 className='text-3xl font-bold text-yellow-600 flex justify-center items-center'>
        FaceIO authentication using react and typescript
      </h1>

    </div>
  );
};

export default Home
Enter fullscreen mode Exit fullscreen mode

Import the signup component to the sign up page.

import SignupForm from '../components/SignupForm';

const SignUp = () => {
  return (
    <div>
      <SignupForm />
    </div>
  );
};

export default SignUp;
Enter fullscreen mode Exit fullscreen mode

Let us now bring the react route dom into the App.tsx so that we are able to route to different pages of our app.

import { BrowserRouter, Route, Routes } from 'react-router-dom';
import Home from './pages/Home';
import SignUp from './pages/SignUp';

function App() {
  return (
    <div className='min-h-screen flex flex-col justify-center items-center'>
      <BrowserRouter>
        <Routes>
          <Route path='/' element={<Home />} />
          <Route path='signup' element={<SignUp />} />
        </Routes>
      </BrowserRouter>
    </div>
  );
}

export default App;
Enter fullscreen mode Exit fullscreen mode

Since now we have finished the arrangement of our site let us get into the gist of our build.

We are going to create a login function to login through FaceIO (remember we had created a signup function in the previous part).

Then we are going to take the user data we get from FaceIO response and pass it into the state using useContext and useReducer.

Setting up useContext in React and Typescript.

Let us create a new folder in src folder named context and in there a file named StateProvider.tsx, in there we will make userContext provider.

import React, {createContext, ReactNode} from 'react';


export const userContext = createContext()


const StateProvider: React.FC<{ children: ReactNode }> = ({ children }) => {
  return(
    <userContext.Provider value={}>
    {children}
  </userContext.Provider>
  )
};

export default StateProvider;
Enter fullscreen mode Exit fullscreen mode

Because we are using typescript we will need to provide types for our build,

in src/@types/user.d.ts we will create the userContext type.

So our createContext will be of type userContextType since when there will be no user the user will be null.

Now let create a folder helpers in src and in it a file named Reducers.ts

/** src/helpers/Reducer.ts */

import { userContextType, Action } from '../@types/user';


//the initial state of the user
export const initialState = {
  user: null,
};


//the action we are going to take when we login that is set the user
export const actionTypes = {
  SET_USER: 'SET_USER',
};


//the reducer function note the parameter type annotations
export const reducer = (state: userContextType, action: Action) => {
  console.log(action);
  switch (action.type) {
    case actionTypes.SET_USER:
      return {
        ...state,
        user: action.user,
      };
    default:
      return state;
  }
};
Enter fullscreen mode Exit fullscreen mode

There is one type we did not define that is the action type let us update it accordingly

Go to src/@types/user.d.ts and add,

type Action = {
  type: 'SET_USER';
  user: Iuser;
};
Enter fullscreen mode Exit fullscreen mode

Now once we are done with this we can update StateProvider as this,

import React, { createContext, ReactNode, useReducer } from 'react';
import { userContextType } from '../@types/user';
import { initialState, reducer } from '../helpers/Reducers';

export const userContext = createContext<{
  state: userContextType;
  dispatch: React.Dispatch<any>;
}>({
  state: initialState,
  dispatch: () => null,
});

const StateProvider: React.FC<{ children: ReactNode }> = ({ children }) => {

//bring the useReducer hook and feed it with the reducer function and the initial state 

  const [state, dispatch] = useReducer(reducer, initialState);
return (

//update the value with the state and dispatch thus you are able to access this values in any component or page

    <userContext.Provider value={{ state, dispatch }}>
      {children}
    </userContext.Provider>
  );
};
Enter fullscreen mode Exit fullscreen mode

Go to App.tsx import the StateProvider and wrap the entire build with it.

<StateProvider>
      <div className='min-h-screen flex flex-col justify-center items-center'>
        <BrowserRouter>
          <Routes>
            <Route path='/' element={<Home />} />
            <Route path='signup' element={<SignUp />} />
          </Routes>
        </BrowserRouter>
      </div>
</StateProvider>
Enter fullscreen mode Exit fullscreen mode

Let us now create a login component to be able to feed user data to the state.

In the folder componets create a file Login.tsx and in it create a login,

import { Link } from 'react-router-dom';
const Login = () => {
  return (
    <div>
      <h1 className='text-3xl font-bold text-blue-600 mb-4'>
        Welcome, please login
      </h1>
      <button className='w-full p-3  bg-blue-700 rounded-md text-white text-sm mb-4'>
        Login
      </button>
<div>
        <p>You don't have an account? Please sign-up.</p>
        <Link to='/signup'>
          <button className='w-full p-3 bg-white outline-blue-800 rounded-md text-blue-800 text-sm mb-4'>
            Sign Up
          </button>
        </Link>
      </div>
    </div>
  );
};
export default Login;
Enter fullscreen mode Exit fullscreen mode

This component will be our gate guard that will refuse anyone admittance to our site unless they have loged in

So in our home component we will need to make some few changes.

We will query whether there is a user in the state that is if user is not null then we will show the home otherwise we will show
the login component

..... return (
    <div className='min-h-screen flex flex-col '>
      {!state?.user ? (
        <Login />
      ) : (
        <div>
          <h1 className='text-3xl font-bold text-yellow-600 flex justify-center items-center'>
            FaceIO authentication using react and typescript
          </h1>
        </div>
      )}
    </div>
  );
Enter fullscreen mode Exit fullscreen mode

This is how your page should look like by now,

login component

Let us now go back to the login component and update the logic, that is call FaceIO and dispatch user data.

When we call FaceIO to authenticate (FaceIO authentication is documented here), and the authentication is successful we will receive a payload with the data the user provided when they signed up. That payload is what we are going to dispatch to the state.

import React, { useContext, useEffect } from 'react';
import { Link } from 'react-router-dom';
import { userContext } from '../context/StateProvider';
import { actionTypes } from '../helpers/Reducers';
const Login = () => {
  //we load faceIO using a useEffect hook
let faceio: any;
  useEffect(() => {
    faceio = new faceIO('fioa48b7');
  }, []);
//we use a useContext hook dispatch to be able to dispatch our user to the state
  const { dispatch } = useContext(userContext);
//we set up the handle login function
  const handleLogin = async () => {
    try {
      let response = await faceio.authenticate({
        locale: 'auto',
      });
      alert(`
        You have been identified successfully
        Unique Facial ID: ${response.facialId}
          PayLoad: ${JSON.stringify(response.payload)}
          `);
dispatch({ type: actionTypes.SET_USER, user: response.payload });
alert('You have successfully logged in');
    } catch (error) {
      console.log(error);
      alert('Failed to login, please refresh and try again');
    }
  };
return (
    <div className='flex flex-col justify-center items-center'>
      <h1 className='text-3xl font-bold text-blue-600 mb-4'>
        Welcome, please login
      </h1>
      <button onClick={handleLogin} className='w-full p-3  bg-blue-700 rounded-md text-white text-sm mb-4'>
        Login
      </button>
<div>
        <p>You don't have an account? Please sign-up.</p>
        <Link to='/signup'>
          <button

            className='w-full p-3 bg-white outline-blue-800 rounded-md text-blue-800 text-sm mb-4'
          >
            Sign Up
          </button>
        </Link>
      </div>
    </div>
  );
};
export default Login;
Enter fullscreen mode Exit fullscreen mode

Once we are done with that our application is good and ready but let us add a welcome user statement in the home page.
Under the h1 tags add.

<h2 className='text-blue-900 pt-28 font-bold'>
   Welcome {state.user.name} Email:{state.user.email}
</h2>
Enter fullscreen mode Exit fullscreen mode

We are now done, if you were successful, and you try loging in you will see,

finished build

The whole of this build can be found in Github, while you are there please add a star to it.

For more on FaceIO

  1. The getting started guide.
  2. The integration guide.
  3. The Developer center.
  4. The frequently asked questions section.
  5. The trust center.

There are also some very interesting articles to get you on your way.

Login/Sign up form using FaceIO, Next.js and Tailwind CSS.

Implementing facial authentication on a Vue.js app.

How to Authenticate a User with Face Recognition in React.js.

That is the conclusion for now but always check back for more content like this.

Top comments (0)