The Easiest Way To Add User Authentication To Your React Project

easybase blog splash image

Update 11/25/2020: easybase-react was recently upgraded to version 1.2.11 which brings performance improvements


React is a library that has allowed developers, novice or expert, to turn their ideas into reality. One of the primary benefits of developing front-end applications with React is the ability to deploy a project on multiple devices and web browsers.

One of the primary features of many web-based projects is the ability to have user authentication in which only those with proper credentials can access certain data. Whether that data is specific to that user or should be available to any signed-in user will depend on the goal of the application. The standard user authentication pattern is to provide unauthenticated users with the ability to sign up/create an account and to those with an account, the ability to sign in. Once signed in, the proper authentication tokens should be provided to the users so they can then access protected data.

Let’s take a look at Easybase’s ‘Project’ feature and React library. These will easily and securely fulfill the authentication pattern as stated above. Along with that, authenticated users can access specific data tables via a stateful and editable ‘database array’. This package works on both React and React Native.


1. Create a new project in Easybase.io

easybase create project

Sign in to your Easybase account. Then, navigate to the ‘Projects’ tab, and create a new project. If you do not have an Easybase account, go create one. The free tier covers almost all use cases.

The service features a visual query builder and self-building API. Also, you have the ability to view your project’s analytics on the fly!


2. Install NPM library

The only extra dependency is the ‘easybase-react’ npm module. To install that, navigate to your React or React Native project and do:

npm i easybase-react

For more information on this package, take a look at it’s Github page.

3. Place ebconfig.js in project root

Expand your newly created project and click ‘download’ to access your ebconfig token.

easybase create React integration

Download the file and place it in the root of your react project, next to App.js.

Note: Under ‘Permissions’, select the tables that you would like your project to be able to access. User’s can be associated with specific records in the table drawer or automatically when they insert/edit a record.


4. Wrap root component in EasybaseProvider

import React, { useEffect } from "react";
import { EasybaseProvider, useEasybase } from "easybase-react";
import ebconfig from "./ebconfig.json";

function App() {
  return (
    <EasybaseProvider ebconfig={ebconfig}>
      <Container />
    </EasybaseProvider>
  );
}

The EasybaseProvider gives all child elements valid access the useEasybase() hook. This hook contains all the stateful functions that are used to interface with your data. Take a look at the documentation here.


5. Allow un-authenticated users to sign in or sign up

The useEasybase() hook provides three functions that are important for your menus workflow. Those being isUserSignedIn, signIn, and signUp. A simple implementation of this workflow could like:

export default function ProjectUser() {
    const [usernameValue, setUsernameValue] = useState("");
    const [passwordValue, setPasswordValue] = useState("");

    const {
        isUserSignedIn,
        signIn,
        signUp,
        getUserAttributes
    } = useEasybase();

    if (isUserSignedIn()) {
        return (
            <div>
              <h2>You're signed in!</h2>
              <button className="btn" onClick={_ => getUserAttributes().then(console.log)}>
                Click me only works if your authenticated!
              </button>
              <FrameRenderer />
            </div>
        )
    } else {
        return (
          <div style={ { display: "flex", flexDirection: "column" } }>
              <h4>Username</h4>
              <input value={usernameValue} onChange={e => setUsernameValue(e.target.value)} />
              <h4>Password</h4>
              <input type="password" value={passwordValue} onChange={e => setPasswordValue(e.target.value)} />
              <button className="btn" onClick={_ => signIn(usernameValue, passwordValue)}>
                Sign In
              </button>
              <button className="btn" onClick={_ => signUp(usernameValue, passwordValue)}>
                Sign Up
              </button>
          </div>
        )
    }
}

If a user has recently signed in, when navigating to this page on the same browser they will automatically be authenticated. Otherwise, once a user successfully signs in the components state will automatically be re-rendered and isUserSignedIn() will return true.

An authenticated user will then be able to access administrative functions such as setUserAttribute. More importantly, they will be able to retrieve an editable data array via Frame().


6. Map elements from Frame()

In our ‘FrameRenderer’ component, we can now configure a Frame() instance and map it to React elements. Remember, the table that you retrieve data from needs to be enabled for read or write in your project’s ‘Permissions’. These elements can feature controls that, when manipulated, directly edit the object. When an object is directly edited, call sync() to synchronize your changes to the could database and re-render your component.

import { useEffect } from "react";

export default function FrameRenderer() {
    const {
        Frame,
        configureFrame,
        sync,
        useFrameEffect
    } = useEasybase();

    useFrameEffect(() => {
      console.log("Frame updated!");
    });

    useEffect(() => {
        configureFrame({
            limit: 10,
            offset: 0,
            tableName: "My Table"
        });
        sync()
    }, []);

    return (
      <div style={ { display: "flex" } }>
        { Frame().map((ele, index) => <CardElement {...ele} index={index} key={index} />) }
      </div>
    )
}

Important: Functions that are only meant for authenticated users, such as sync() and setUserAttribute, only work when an instance is signed in and is not accessible via an unauthorized user or third party.

Regarding Frame(), we can think of the easybase-react lifecycle as follows:

Frame Is Synchronized ->
useFrameEffect() runs ->
Edit Frame() ->
Call sync() ->
Frame Is Synchronized ->
useFrameEffect() runs

Conclusion

Learn more about Easybase’s mission here

User authentication and scalable database integration is an integral part of almost all production applications and services. At some point, a developer is going to need to be able to securely and asynchronously access their data from a fast & reliable source. Easybase is a cloud-service that makes developer’s lives easier through a serverless framework and scalable database.