snow-mountain

Implementing Okta Authentication in React


Last updated on
Web Development

Summary (TL;DR): Okta is an identity manager for securing every identity, with features such as single sign-on and multi-factor authentication. Okta can be used for securing the identity of customers and workforces. In this tutorial, we are going to learn how to use Okta for authentications in React applications. We’ll cover the core concepts of Okta, use cases for it, and why you should use it in your next React application.

One essential factor to consider when building an application is authentication. For many developers, building their authentication architecture is fairly straightforward. Still, when you start considering things like security and integration with third-party platforms such as Google and Facebook, the process of building your authentication system becomes more complex.

This tutorial will be beneficial to readers who are interested in learning how to authenticate users with Okta and other alternatives in their React applications. This article requires a basic understanding of React and JavaScript.

While You Are at It, Why Not Learn More About The Newest Version of React – React 18

Table of Contents

Authentication in React Applications
How Does Okta Work?
What Is Okta?
Why Use Okta?
Building an Application With Okta
>> Setting Up Okta
>> Creating a React Application
>> Configuring Okta for React Application
>> Configuring Okta in React App
>> Building App Components
>> Building a Room Card Component
>> Creating a Data Table
>> Creating a User Auth Hook
>> Creating a Home Page
>> Building Profiles Page
>> Completing Our Application

Authentication in React Applications

React applications are a mixture of pages that are available for everyone and some require a form of authentication. With authentication, React developers can validate user-specific details to determine if the user is authenticated and then assign a role to the user. Roles can include simple client access or more sophisticated admin access. Users will need to perform the following:

  1. Sign up: this can be done with an email, phone number and a password and save the user’s info for when they next want to access their private pages.
  2. Log in: Here’s how authenticated users should be able to login to their own private pages.

Authentication in React applications can be done in a variety of ways, some of which include the use of native authentication methods such as token-based authentication tools like JWTs, the use of libraries like stormpath and the use of authentication managers like Auth0, Okta and OneLogin. 

How Does Okta Work?

Like many authentication managers, Okta allows developers to control access to your React application using the OAuth2.0 specifications. Okta can be used as an authorization server to store all user information and issue user tokens for authentication and authorization.

With Okta, all your user data and authentication information is stored securely on the cloud by Okta and can be managed from your Okta admin dashboard.

To retrieve your user data from Okta, you’d need to access it using Okta using a getUser method on OktaAuthService. You can read more here.

What Is Okta?

Okta is an enterprise-level Identity-as-a-service cloud platform that is used for authorization by individuals and organizations. Unlike several identity platforms, Okta works perfectly with on-premises applications and cloud applications. 

With Okta, project and IT managers can manage access to employees on all resources and applications in an organization. Okta runs effectively in the Cloud on a secure platform and is integrated with an on-premises directory, applications, and identity management systems. 

The Core Concept of Okta includes the following methods and features.

  • Okta Identity Engine: This is the core feature of Okta. It allows users to customize their Okta cloud components to solve a wide range of authorization use cases. This feature allows users to use more than the default auth features defined by Okta and create customized solutions to their identity needs. 
  • Single Sign-On(SSO): With Okta, users have a single inbuilt sign-on accessibility feature for Cloud and mobile applications. Once you’ve logged in with your Okta account, you can access your application on any other device without needing to re-enter your credentials. Users can also integrate Okta with their on-premises applications and Cloud-based applications. 
  • Okta Provisioning: To automate user account and management processes, Okta provides advanced lifecycle hooks. Users can use the built-in Okta integration network or a custom API connection to support users between Okta and Cloud. Okta also provides a web API for managing user accounts. 
  • Okta Mobility Management: This feature enhances the management and identity of users. Through Okta mobile management, project and product managers can manage access policies from a central cloud-based console. This provides high protection to data, people, and apps from directories to any mobile device. To prevent unauthorized users from accessing some endpoints, Okta allows users to build contextual user accesses.

Why Use Okta?

Okta’s main objective is to improve enterprise-level authorization and identity management for IT teams and organizations and make it easier for users to manage permission. 

Okta also provides sign-in widgets and advanced lifecycle management hooks for authenticating users. Also, Okta provides organizations with customizations that allow them to extend their identity management needs. There are several identity managers available for React and React Native applications. This includes Azure AD, Onelogin, and Auth0. Let’s look at the table below on why Okta is often regarded as a smarter choice for teams and organizations. 

                 Okta        One Login     Azure AD
1. Provides 2 Factor Authentication Provides 2FA Provides 2FA 
2. Provides batch permissions and access for large organizations Do not provide batch permissions or access Provides batch permissions for a select admin roles 
3. Data import and export for teams and individuals Do not provide Data import and export for teams and individualsData import and export for teams and individuals
4. Email and Google Apps integration Do not provide email or google apps integrationData import and export for teams and individuals
5. Proficient cross-platform capabilitiesLimited cross-platform capability Limited cross-platform capability 

Building an Application With Okta

Now that we know the core concept of Okta, we’ll be building a Rent management system. The application will allow a landlord to see information about his tenants, the house number, an image of the room, and a tenant’s information. Using Okta, the landlord and tenant will be able to log in and view this information. 

Without further ado, let’s start!

Setting Up Okta

The first requirement is to create an account on Okta. Doing this allows us to create and onboard users to our Okta admin dashboard. Here, we will assign a sign-in method using Okta sign-in and also add an application type to our Okta dashboard. You can see this in the image below. 

Okta Create Application

After clicking on the Applications tab, navigate to the button Create App Integration.

Creating a single page application

Here, we select the OpenID Connect Sign-in method. This provides us with a sign-in widget from Okta (this is optional, you can also build your custom login). Next, we selected our application type, which is a single-page application. Click on the Next button after selecting these credentials. 

Next, we will specify the Sign-in URI and Sign-out URI, we will also redirect URIs localhost:3000 for this tutorial as seen below:

Okta signed into URI

In the image above, we added a sign-in redirect URL to redirect users after they log in to our application and a Sign-Out URL to redirect users after they log out. 

On our Okta Dashboard, we can configure the type of authentication we want for our users and add sign-in and sign-out routes. We’re now ready to create our React application with Okta!

Creating a React Application

Let’s get started with creating a React application using the Create React App. Run the command below to create a new project:

npx create-react-app {project name}

Alternately, you can use Yarn:

yarn create-react-app {project name}

Next, cd into the project directory and start your development server using the command below:

cd {project name} && yarn run dev

Configuring Okta for React Application

Now, we’ll install @okta/okta-react, @okta/okta-signin-widget and @okta/okta-auth-js dependencies in our application:

Using NPM:

npm install @okta/okta-react @okta/okta-signin-widget @okta/okta-auth-js

Using Yarn:

yarn add @okta/okta-react @okta/okta-signin-widget @okta/okta-auth-js

Next, let’s install dotenv package, which we’ll use for storing our Okta environment variables. We’ve also added styled-components that we’ll use for styling our application:

Using Yarn:

yarn add dotenv styled-components

Using NPM:

npm install dotenv styled-components

Create a new file.env in the root directory of your project and add the following credentials, provided by Okta:

REACT_APP_OKTA_BASE_URL="your okta base URl goes here"
REACT_APP_OKTA_CLIENT_ID="your unique ID goes here"

The BASE_URL is a combination of your login email hosted by Okta. This is a public identifier for 0Auth flows provided by Okta. Your CLIENT_ID can be found on your Okta dashboard under your Client credentials. Next, let’s complete our Okta authentication by setting up a user for our application below.

Configuring Okta in React App

To use Okta for our React application, we will first need to initialize a primary user in our application. First, create a new file called config.js in the root directory of our project application, and inside it, add the code block below:

export const oktaAuthConfig = {
    issuer: `https://${process.env.REACT_APP_BASE_URL}/oauth2/default`,
    clientId: process.env.REACT_APP_CLIENT_ID,
    redirectUri: `${window.location.origin}/login/callback`,
    scopes: ["openid", "profile", "email"],
    pkce: true,
};

In the code block above, first, we created an object called oktaAuthConfig, and inside it, we created an issuer, our base_URL, and clientID from Okta. The redirect Uri is the callback we set up on our Okta dashboard. You can read more about the Okta React configuration in the docs.

Building App Components

Create a Navbar.js file in src/components/Navbar directory. Next, we will create a functional Navbar component with two Okta-assisted links for logging in and signing out. Let’s do that below:

import { Link } from "react-router-dom";
import styled from "styled-components";
import { useOktaAuth } from "@okta/okta-react";

const Navbar = () => {
    const { oktaAuth, authState } = useOktaAuth();

    const login = async () => oktaAuth.signInWithRedirect({ originalUri: "/" });

    const logout = async () => oktaAuth.signOut();

In the code above, we imported useOktaAuth from Okta. Using the useOktaAuth hook, we get access to our Okta state and oktaAuth object. For our login, we created a function login that will call oktaAuth sign-in to sign in a user and another function logout for signing out a user. 

Next, we created a button, and inside it we render a login button to the user if they’re not authenticated yet and if the user is authenticated, we will render a logout button.

To complete our component, we will add styles and a navbar menu that will contain the name of the estate and a link to a profile page for users, Let’s do that below:

   return (
        <Container>
            <Link to="/">
                <h2>SilverJoy Estate</h2>
            </Link>
            <ul>
                <li>
                    <Link to="/profile">Profile</Link>
                </li>
                <li>
                    {
                      authState?.isAuthenticated ? (
                            <button onClick={logout}>Logout</button>
                        ) : (
                            <button onClick={login}>Login</button>
                        )
                    }
                </li>
            </ul>
    </Container>
};

Let’s add styles to our application, export the component and see the results of the component below:

const Container = styled.nav`
    width: 90%;
    margin: 1rem auto;
    display: flex;
    align-items: center;
    justify-content: space-between;
    a {
        text-decoration: none;
    }
    h2 {
        font-style: oblique;
    }
    & ul {
        display: flex;
        align-items: center;
        justify-content: space-between;
        & li {
            list-style-type: none;
            &:nth-last-child(1) {
                margin-left: 1rem;
            }
            &:hover {
                text-decoration: underline;
            }
            a {
                font-size: 1rem;
                text-decoration: none;
                color: #333;
                font-weight: 500;
            }
            & button {
                outline: none;
                border: none;
                background: transparent;
                font-size: 1rem;
                color: #333;
                font-weight: 500;
                cursor: pointer;
            }
        }
    }
`;
export default Navbar;

Our Navbar component should look like the image below:

Okta Navbar component

Building a Room Card Component

In this section, we will build a Card component for rendering each room in the estate. We’ll create a simple component to render the occupant’s name, room number, and the rent due date. 

Let’s do this by first creating a new folder called RoomCard in the components folder and inside it, add a new file called RoomCard.js, and inside it add the code block below:

import styled from "styled-components";

const CardWrapper = styled.div`
    box-shadow: -2px 7px 8px 3px rgba(204, 204, 204, 0.63);
    width: 15rem;
    border-radius: 7px;
    & > .bg {
        background: url(${(props) => props.coverImg}) no-repeat center center/cover;
        height: 10rem;
    }
    & .body {
        padding: 0.5rem 0 1rem;
        display: flex;
        flex-direction: column;
        align-items: center;
        h4 {
            text-align: center;
        }
        footer {
            margin-top: 0.7rem;
            & p {
                font-size: 0.9rem;
            }
        }
    }
`;

const RoomCard = ({ roomNo, occupantName, rentDueDate, coverImg }) => {
    return (
        <CardWrapper coverImg={coverImg}>
            <div className="bg" />
            <div className="body">
                <h4>Room No: {roomNo}</h4>
                <footer>
                    <p>Occupant: {occupantName}</p>
                    <p>Rent Due Date: {rentDueDate}</p>
                </footer>
            </div>
        </CardWrapper>
    );
};

export default RoomCard;

In the code above, we created a component, the CardWrapper component, that contains our props. This component will be the skeleton component for rendering the details of our occupants, we also created styles with styled-components.

Next, we imported styled-components for styling this component. We created a form component that takes roomNo, occupant name, rent due date, and covering as props

Creating a Data Table 

Here, we will create an object containing all the occupants’ information in our estate application. In the root directory of our application, create a new file data.js, and inside it, let’s add some occupants and their details as an object below:

export const lodgeData = [
    {
        id: 1,
        roomNo: 1,
        coverImg:
            "https://images.unsplash.com/photo-1522708323590-d24dbb6b0267?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=750&q=80",
        occupantName: "Ikechi Fortune",
        rentDueDate: "01-09-2021",
    },
    {
        id: 2,
        roomNo: 2,
        coverImg:
            "https://images.unsplash.com/photo-1537726235470-8504e3beef77?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=750&q=80",
        occupantName: "Origho Precious",
        rentDueDate: "31-10-2021",
    },
    {
        id: 3,
        roomNo: 3,
        coverImg:
            "https://images.unsplash.com/photo-1552242718-c5360894aecd?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=750&q=80",
        occupantName: "Ikeh Yemi",
        rentDueDate: "04-01-2022",
    },
    {
        id: 4,
        roomNo: 4,
        coverImg:
            "https://images.unsplash.com/photo-1610123172763-1f587473048f?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=346&q=80",
        occupantName: "Melvin Manni",
        rentDueDate: "01-08-2021",
    },
    {
        id: 5,
        roomNo: 5,
        coverImg:
            "https://images.unsplash.com/photo-1550581190-9c1c48d21d6c?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=698&q=80",
        occupantName: "Uma Victor",
        rentDueDate: "11-09-2021",
    },
    {
        id: 6,
        roomNo: 6,
        coverImg:
            "https://images.unsplash.com/photo-1550581190-9c1c48d21d6c?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=698&q=80",
        occupantName: "Isaac Ugo",
        rentDueDate: "11-09-2021",
    },
];

In the code above, we have added a list of occupants and details to them. 

Creating a User Auth Hook

Here, we will create a hook for getting the user’s details and authenticate them. To do this, in the root directory of your application, create a new folder hooks and inside them create a new file getUser.js, add the code below:

import { useEffect, useState } from "react";
import { useOktaAuth } from "@okta/okta-react";

const useAuthUser = () => {
        const { oktaAuth, authState } = useOktaAuth();
        const [userInfo, setUserInfo] = useState(null);

        useEffect(() => {
                const getUser = async () => {
                        try {
                                const res = await oktaAuth.getUser();
                                setUserInfo(res);
                        } catch (error) {
                                console.log(error);
                        }
                };

                authState?.isAuthenticated && getUser();
        }, [authState, oktaAuth]);

        return userInfo;
};

export default useAuthUser;

To complete our application, we will build our Home and Profile pages using the components we’ve built in this section in section. Let’s do this below:

Creating a Home Page

Here, we will create our Home page using our RoomCard component; this Page will get users’ information when they log in and display it with a welcome message. This Page will also contain all rooms and occupants’ details. 

We will create a new folder pages in the root directory of our application, inside it create a new directory home, this folder will contain a file index.js, add the code block below:

To handle authentication, we imported useOktaAuth from okta-react. For styling our Page, we imported styled components. We will create a data.js file that will contain all the information we will render on this Page. We will create a function to get the user’s details from Okta and set it in our application state in the code block below:

Next, we will build a welcome screen and render a list of all the occupants of our estate. Let’s do this below:

import { useOktaAuth } from "@okta/okta-react";
import useAuthUser from "../../hook/getUser";
import styled from "styled-components";
import { lodgeData } from "../../data";
import RoomCard from "../../components/RoomCard/RoomCard";

const Home = () => {
    const { authState } = useOktaAuth();
    const userInfo = useAuthUser();

return (
        <Wrapper>
            {authState?.isAuthenticated ? (
                <>
                    <h2>Welcome back, {userInfo?.name}</h2>
                    <article>
                        {lodgeData.map(
                            ({ id, coverImg, roomNo, occupantName, rentDueDate }) => (
                                <div key={id} className="card">
                                    <RoomCard
                                        coverImg={coverImg}
                                        roomNo={roomNo}
                                        occupantName={occupantName}
                                        rentDueDate={rentDueDate}
                                    />
                                </div>
                            )
                        )}
                    </article>
                </>
            ) : (
                <p style={{ textAlign: "center", marginTop: "6rem", fontSize: '2rem' }}>
                    Please login to see data
                </p>
            )}
        </Wrapper>
    );
};

In the code above, we are checking if a user is authenticated. If they are, we display a welcome message with the user’s name and a list of cards containing all the information on the estate occupants. To conclude our application, we will add some styles in the code block below:

const Wrapper = styled.section`
    max-width: 90%;
    margin: 2rem auto;
    & h2 {
        font-size: 1.3rem;
        font-weight: 500;
        margin-bottom: 2rem;
    }
    & > article {
        width: 95%;
        margin: auto;
        display: flex;
        flex-wrap: wrap;
        .card {
            margin: 1rem;
        }
    }
`;
export default Home;

In the code block above, we added styles to our Home page, if done correctly our application should look like the image below:

Home page Okta

In the next section, we will build our profile page for our primary user.

Building Profiles Page

In this section, we will build a profiles page for our application. This Page will render user details, including the username, email, names, and a verified email from Okta. In the page directory of our application, create a new folder called Profile and inside it create a new file index.js and add the code block below:

import useAuthUser from "../../hook/getUser";
import styled from "styled-components";

const Profile = () => {
        const userInfo = useAuthUser();

    return (
        <Wrapper>
            <h2>My Profile Details</h2>
            <article>
                <ul>
                    <li>Username: {userInfo?.preferred_username}            </li>
                    <li>Email: {userInfo?.email}</li>
                    <li>Full Name: {userInfo?.name}</li>
                    <li>Family Name:{userInfo?.family_name}               </li>
                    <li>Given Name: {userInfo?.given_name}                  </li>
                    <li>Email Verified: {userInfo?.email_v                      erified ? "Yes" : "No"}
                </li>
                    <li>Zone: {userInfo?.zoneinfo}</li>
                </ul>
            </article>
        </Wrapper>
    );
};

Similar to our Home page, we are getting the user’s details from Okta after they are logged in to our application. We then created a Wrapper component that displays the logged-in user details. To complete our application, let’s add styles to our Page.

const Wrapper = styled.section`
    max-width: 90%;
    margin: 2rem auto;
    & h2 {
        font-size: 1.3rem;
        font-weight: 500;
        margin-bottom: 1rem;
    }
    & ul {
        width: 50%;
        list-style: none;
        display: grid;
        grid-template-columns: repeat(2, 1fr);
        background: #f2f3f5;
    padding: 1rem 2rem;
        & li {
            margin: 0.7rem 0;
            font-size: 1rem;
        }
    }
`;

export default Profile;

We added the wrapper component to the code block above and exported our Page as a page. If we notice that our app isn’t complete because we’ve not configured our Okta authentication to enable a user to log in, we will configure a data table of estate occupants in our next section.

Completing Our Application

To complete our application, let’s add routes to our application. The routes enable Okta to know which users to give specific access to. In our case, we will provide all access to the primary user, which is the email used to register for your Okta application.

We will first create a new file called Routes in the root directory of our application and add the code snippet below:

import { Route, Switch, useHistory } from "react-router-dom";
import { Security, SecureRoute, LoginCallback } from "@okta/okta-react";
import { OktaAuth, toRelativeUrl } from "@okta/okta-auth-js";
import Home from "./pages/home";
import Profile from "./pages/profile";
import { oktaAuthConfig } from "./config";
import Navbar from "./components/Navbar/Navbar";

const oktaAuth = new OktaAuth(oktaAuthConfig);
const Routes = () => {
    const history = useHistory();

    const restoreOriginalUri = async (_oktaAuth, originalUri) => {
        history.replace(toRelativeUrl(originalUri || "/", window.location.origin));
    };
    return (
        <Security oktaAuth={oktaAuth} restoreOriginalUri={restoreOriginalUri}>
            <Navbar />
            <Switch>
                <Route path="/" exact={true} component={Home} />
                <SecureRoute path="/profile" component={Profile} />
                <Route path="/login/callback" component={LoginCallback} />
            </Switch>
        </Security>
    );
};

export default Routes;

In the code above, we created a function Routes, which redirects a user to our application after they log in on Okta sign-in widget. We initialized a new Okta app using Okta config, the storage URL fixes our okta login, the security package is from Okta used to handle authentication in our application. 

The login route handles a user’s login. Next, we added routes for our Home, Profile, and Callback pages. For security, we imported the security package from Okta.

To complete our application, one more thing to do is to import our Routes in our App.js file, as shown below.

import { BrowserRouter } from "react-router-dom";
import Routes from "./Routes";

const App = () => {
        return (
                <BrowserRouter>
                   <Routes />
                </BrowserRouter>
        );
};

export default App;

Here, we imported our Routes file which contains the routes for our application and permissions. Our application should look like the image below:

Conclusion

Authentication and authorization are two of the essential features in building web applications. This article taught about Okta, an Identity as a Service platform built for seamless authentication and authorization. We also went through the process of building an estate manager application with React. The code for our React estate application can be found here.