Implementing Okta Authentication In React

About The Author

Topple is a curious cat that likes to learn something new every day. It also likes to write on behalf of authors who are a bit too shy, and Topple totally … More about Topple ↬

Email Newsletter

Weekly tips on front-end & UX.
Trusted by 200,000+ folks.

Okta is an identity manager, with features such as single sign-on and multi-factor authentication. Okta can be used to secure the identities of customers and workforces. In this tutorial, we are going to learn how to use Okta for authentication in a React application. We’ll understand the core concepts of Okta, use cases, and why you should use it in your next React application.

When we’re building an application, one essential factor is authentication. For many developers, building an authentication architecture is straightforward. Still, teams have to consider security and ease of integration with third-party platforms such as Google and Facebook. Soon enough, building your own authentication system becomes complex.

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

Authentication In React Applications

Most React applications are a mixture of pages that are available to everyone and pages that require some form of authentication. React developers need to validate user-specific details to determine whether a user is authenticated and then assign a role to that user. Roles range from simple client access to more sophisticated admin access. Users generally need to do the following:

  1. Sign up
    This can be done with an email address, phone number, and password, and you would save the user’s information for when they next want to access those private pages.
  2. Log in
    Authenticated users need to be able to log in to their own private pages.

Authentication in a React application can be done in a variety of ways, including native authentication methods (for example, token-based authentication tools like JSON Web Tokens (JWTs)), libraries such as Stormpath, and authentication managers such as Auth0, Okta, and OneLogin.

How Does Okta Work?

Like many authentication managers, Okta allows developers to control access to a React application using the OAuth 2.0 specification. Okta can be used as an authorization server to store all user information and issue user tokens for authentication and authorization.

With Okta, all of the user’s data and authentication information is stored securely in the cloud by Okta and can be managed from the Okta admin dashboard.

To retrieve user data from Okta, you’ll need to access it using Okta’s getUser method on OktaAuthService. More information is available in the documentation.

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 other 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 the organization. Okta runs effectively in the cloud on a secured platform and integrated with on-premises directories, applications, and identity-management systems.

The core of Okta includes the following methods and features:

  • Okta Identity Engine
    This is the core feature of Okta. It allows managers to customize their Okta cloud components to solve a wide range of authorization use cases. Managers can use more than the default authorization features defined by Okta and can create customized solutions to their identity needs.
  • Single Sign-On (SSO)
    With Okta, managers have a single built-in sign-on accessibility feature for cloud and mobile applications. Once you’ve logged in with your Okta account, you will be able to access your application on any other device without needing to re-enter your credentials. You can also integrate Okta with their on-premises and cloud-based applications.
  • Okta Provisioning
    For automating users’ account and management processes, Okta provides advanced lifecycle hooks. Managers 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 identities of users. From 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 managers to build contextual user access.

Why Use Okta?

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

Okta also provides sign-in widgets and advanced lifecycle-management hooks to authenticate users. The customizations will allow an organization to extend its identity-management needs. Several identity managers are available for React and React Native applications, including Azure AD, OneLogin, and Auth0. The table below shows why Okta is often regarded as a smarter choice for teams and organizations.

OktaOneLoginAzure AD
Provides 2-factor authenticationProvides 2FAProvides 2FA
Provides batch permissions and access for large organizationsDoes not provide batch permissions and accessProvides batch permissions for select admin roles
Data import and export for teams and individualsDoes not provide data import and export for teams and individualsData import and export for teams and individuals
Email and Google Apps integrationDoes not provide email and Google Apps integrationData import and export for teams and individuals
Proficient cross-platform capabilitiesLimited cross-platform capabilityLimited cross-platform capability

Build An Application With Okta

Now that we know the core features of Okta, let’s build a rent-management system. This application will allow a landlord to see information about each tenant, the house number, and an image of the room. Using Okta, a landlord and a tenant will be able to log in and see this information.

Without further ado, let’s start!

Set Up Okta

The first requirement is to create an account on Okta. This will allow us to create an application and to 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 in our Okta dashboard. You can see this in the image below.

Okta dashboard to create app
Okta dashboard to create application. (Large preview)

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

Creating a SPA in Okta
Creating a single-page application. (Large preview)

Here, we selected the “OpenID Connect” sign-in method. This provides us with a sign-in widget from Okta (this is optional — you can also build a custom log-in). 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 a sign-in URI and a sign-out URI. We will set our redirect URIs to localhost:3000 for this tutorial, as seen below:

Okta sign-in URI
Okta sign-in URI. (Large preview)

As shown in the image above, we added a sign-in redirect URI to redirect users once they’ve logged in to our application and a sign-out URI to redirect users once they’ve logged out.

In our Okta dashboard, we can configure the type of authentication that we want for users and add sign-in and sign-out routes. Now, we’re ready to create our React application with Okta!

Creating A React Application

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

npx create-react-app {project name}

Alternatively, 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

Configure Okta for the React Application

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

Use this for npm:

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

And use this for Yarn:

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

Next, let’s install the dotenv package, which we’ll use to store our Okta environment variables. We also add styled-components, which we’ll use to style our application.

Using npm:

npm install dotenv styled-components

Using Yarn:

yarn add dotenv styled-components

Create a new file, .env, in the root directory of our 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 includes your log-in email hosted by Okta. It’s a public identifier for OAuth flows provided by Okta. Your CLIENT_ID can be found in your Okta dashboard under the client credentials. Next, let’s complete our Okta authentication by setting up a user for our application.

Configure Okta in React App

To use Okta for our React application, first, we will need to initialize a primary user in our application. Create a new file, config.js, in the root directory of our project application, and in 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 this code block, we’ve created an object named oktaAuthConfig. In that, we created an issuer, our BASE_URL, and a clientID from Okta. The redirectUri is the callback that we set up in our Okta dashboard. You can read more about Okta React configuration in the documentation.

Building App Components

Create a Navbar.js file in the src/components/Navbar directory. We’ll 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 Nav = () => {
        const { oktaAuth, authState } = useOktaAuth();
        const loggingIn = async () => oktaAuth.signInWithRedirect({ originalUri: "/" });
        const loggingOut = 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 logging in, we created a function, login, that will call oktaAuth to sign in a user, and another function, logout, to sign them out.

Next, we created a button. In it, we rendered log-in functionality to the user if they’re not authenticated yet, and we rendered log-out functionality if the user is authenticated.

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

    return (
        <Section>
            <Link to="/">
                <h2>Regents Housing</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>
    </Section>
};

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

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

Our Nav component should look like the image below:

Okta Navbar component
Okta Navbar component. (Large preview)

Building A Room Card Component

In this section, we will build a Card component to render 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 folder named RoomCard in the components folder. In it, add a new file named RoomCard.js, and in that add the code block below:

import styled from "styled-components";

const Card = ({ roomNo, occupantName, rentDueDate, coverImg }) => {
    return (
        <Wrapper 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>
        </Wrapper>
    );
};

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

export default Card;

Here, we’ve created a component, CardWrapper, that contains our props. This component will be the skeleton component to render the details of our occupants. We also created styles with styled-components.

Next, we imported styled-components to style this component. We created a form component that takes roomNo, occupantName, rentDueDate, and coverImg as props.

Creating A Data Table

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

export const Data = [
    {
            id: 1,
            roomNo: 1,
            coverImg:
                " https://images.unsplash.com/photo-1653463174260-8e974b584704?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1587&q=80",
            occupantName: "Fortune",
            rentDueDate: "01-09-2021",
        },
        {
            id: 2,
            roomNo: 2,
            coverImg:
                "https://images.unsplash.com/photo-1653191252464-c3f61798ce9a?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHx0b3BpYy1mZWVkfDEwfFJfRnluLUd3dGx3fHxlbnwwfHx8fA%3D%3D&auto=format&fit=crop&w=500&q=60",
            occupantName: "Yemi",
            rentDueDate: "04-01-2022",
        },
        {
            id: 3,
            roomNo: 3,
            coverImg:
                "https://images.unsplash.com/photo-1538430989507-797d5e4ba836?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHx0b3BpYy1mZWVkfDEzfFJfRnluLUd3dGx3fHxlbnwwfHx8fA%3D%3D&auto=format&fit=crop&w=500&q=60",
            occupantName: "Precious",
            rentDueDate: "31-10-2021",
        },
        {
            id: 4,
            roomNo: 4,
            coverImg:
                "https://images.unsplash.com/photo-1600947871775-082dd97e2d96?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHx0b3BpYy1mZWVkfDExfFJfRnluLUd3dGx3fHxlbnwwfHx8fA%3D%3D&auto=format&fit=crop&w=500&q=60",
            occupantName: "Isaac",
            rentDueDate: "11-09-2021",
        },
        {
            id: 5,
            roomNo: 5,
            coverImg:
                "https://images.unsplash.com/photo-1651342490124-c2042b78d41c?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHx0b3BpYy1mZWVkfDIzfFJfRnluLUd3dGx3fHxlbnwwfHx8fA%3D%3D&auto=format&fit=crop&w=500&q=60",
            occupantName: "Victor",
            rentDueDate: "11-09-2021",
        },
        {
            id: 6,
            roomNo: 6,
            coverImg:
                "https://images.unsplash.com/photo-1653162100655-88a23594835f?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHx0b3BpYy1mZWVkfDI2fFJfRnluLUd3dGx3fHxlbnwwfHx8fA%3D%3D&auto=format&fit=crop&w=500&q=60",
            occupantName: "Melvin",
            rentDueDate: "01-08-2021",
        },
];

Here, we’ve added a list of occupants and their details.

Creating A User Authentication Hook

Let’s create a hook to get the user’s details and authenticate them. To do this, in the root directory of our application, create a new folder, hooks, and in it 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 that we built in this section. Let’s do that now.

Creating The Home Page

Let’s create the home page using our RoomCard component. This page will get the user’s information when they log in and display a welcome message. It will also contain all rooms and details of occupants.

Create a new folder, pages, in the root directory of our application. In it, create a new directory, home, which will contain the file index.js. We’ll be adding code to it shortly.

To handle authentication, we imported useOktaAuth from okta-react. To style our page, we imported styled-components. Let’s create a data.js file that contains all of the information to be rendered on this page. We will create a function to get the user’s details from Okta, and then set it in our application’s state. Then, we will build a welcome screen and render a list of all occupants of our estate. Let’s do that:

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

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

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

In the code above, we are checking whether the user is authenticated. If they are, then we display a welcome message with the user’s name and a list of cards containing all of the information about the estate’s occupants. To finish off our application, let’s add some styles:

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

Here, we’ve added styles to our home page. If done correctly, our application should look like this:

Okta home page
Okta home page (Large preview)

In the next section, we will build the profiles page of our primary user.

Building Profiles Page

In this section, we will build a profiles page for our application. This page will render the details of users, including username, email address, name, and a verified email from Okta. In the pages directory of our application, create a new folder, Profile, and in it create a new file, index.js, adding the code block below:

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

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

    return (
        <Container>
            <h2>My Profile Details</h2>
            <section>
                <ul>
                    <li>Username: {userInfo?.preferred_username}</li>
                    <li>Email: {userInfo?.email}</li>
                    <li>Full Name: {userInfo?.name}</li>
                    <li>Email Verified: {userInfo?.email_verified ? "Yes" : "No"} </li>
                    <li>Zone: {userInfo?.zoneinfo}</li>
                </ul>
            </section>
        </Container>
    );
};

Similar to our home page, here we are getting the user’s details from Okta once they are logged in to the application. We then created a Wrapper component that displays the logged-in user’s details.

To complete our application, let’s add styles to our page.

const Container = 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: flex;
            flex-direction: column;
            background: #f2f3f5;
            padding: 1rem 2rem;
            & li {
                margin: 0.7rem 0;
                font-size: 1rem;
            }
        }
    `;

export default Profile;

We added the wrapper component in the code block above and exported our page as a page.

Our app isn’t complete yet because we haven’t configured our Okta authentication to enable a user to log in. So, we will configure a data table of estate occupants in the next section.

Okta profile component
Okta profile component. (Large preview)

Completing Our Application

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

Let’s create a file, 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 Nav from "./components/Navbar/Nav";

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, that redirects the user to our application once they’ve logged in using the Okta sign-in widget. We initialized a new Okta app using Okta config. The storage URL sets our Okta log-in. And the security package from Okta handles authentication in our application.

The log-in route handles the user’s log-in. Next, we added routes for our Home, Profile, and Callback pages. And we imported the security package from Okta.

To complete our application, let’s import the routes to 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;

We’ve imported the Routes file, which contains the routes for our application and permissions. Our application should now look like the image below.

Okta React app
Okta React App. (Large preview)

Conclusion

Authentication and authorization are two essential features in web applications. This article has gone through Okta, an identity-as-a-service platform built for seamless authentication and authorization. We also went through the process of building an estate manager’s application with React. The code for our React estate application can be found on GitHub.

Resources

Smashing Editorial (ks, yk, il, al)