Modern web development presents a number of issues, one of which is authentication, which is both critical and frequently overlooked. Authentication is often not implemented correctly resulting in major security breaches.
This article aims to teach developers how to utilize user authentication to secure a React application with the help of Auth0’s React SDK which offers a high-level API for dealing with a variety of authentication related concerns while writing less code.
We will also use the cloud-based media management tools within -Cloudinary to manage media-related assets needed.
Prerequisites
To follow the steps in this article, we should have:
- Adequate knowledge of JavaScript and React.js.
- The latest version of Node.js installed.
- A terminal such as ITerm2(Mac OS) or Git bash (Windows).
- A Cloudinary account - Create one for free here.
- An Auth0 account - Create one for free here.
If you need to look at the source code, it's available on Github and Codesandbox. Also see the deployed application on Netlify.
NOTE: Because Codesandbox provides 2 different hosts with different URLs, open the app browser on Codesandbox in a new window for it to be authorized by Auth0. Click here to access the app in a new window.
Setting up our Cloudinary account
After successfully creating an account, Cloudinary will redirect to our account's dashboard page, where we can see account details that will be useful later on, including:
- Cloud Name
- API Key
- API Secret
NOTE: Do not share these details with anyone.
Setting up our React Auth0 account
Once we sign in, Auth0 takes us to the Dashboard. In the left sidebar menu, click on "Applications". Then, click the "Create Application" button. A modal opens up with a form to provide a name for the application and choose its type. Click on “Single Page Web Applications” as its type, then click on "Create". Go to the "Settings" tab of your Auth0 Application page and fill the following with our localhost URL(http://localhost:3030
):
- Allowed Callback URLs - A list of URLs that will be called back when the user authenticates.
- Allowed Logout URLs - A list of valid URLs to redirect to after logging out of Auth0.
- Allowed Web Origins - Comma-separated list of allowed origins for use with Cross-Origin Authentication.
Scroll down and click the "Save Changes" button.
From the Auth0 Application Settings page, we will need the Auth0 Domain and Client ID values later.
NOTE: Do not share these details with anyone.
Installing the project dependencies
Next, create a react app and move into the app directory:
npx create-react-app meme-gen
cd meme-gen
After that install react-router-dom
, cloudinary
, and Auth0
with the following commands:
#install react-router-dom, cloudinary and Auth0 for React SDK
npm install react-router-dom
npm install cloudinary-react
npm install @auth0/auth0-react
Running npm start
should render an app with an affirmative message on our browser:
Defining our components
While still in development, replace the default syntax in App.js
with this:
import React, { useState } from 'react';
import './App.css';
function App() {
return (
<main className="main">
<div className="title">
<h2>meme generator</h2>
</div>
</main>
);
}
export default App;
Generating sample data
Next, we will need to create and fill a Data.js
file with the URL of our images; here's a sample of the data we will be using:
const memes = [
{
id: 1,
img: 'meme/livingroom.jpg',
},
{
id: 2,
img: 'meme/tiktok.jpg',
},
{
id: 3,
img: 'meme/flush.jpg',
},
{
id: 4,
img: 'meme/million.jpg',
},
{
id: 5,
img: 'meme/wiki.jpg',
}
];
export default memes;
Create a file and define two useState
variables to:
- Access data from
Data.js
- Set the index of our data, with an initial value of 0.
Using the Cloudinary elements from the cloudinary-react
library, import the necessary images from Cloudinary, then apply the Cloud name from our account details and also include the name of the image in the Image
component:
import {Image, Transformation, CloudinaryContext} from 'cloudinary-react';
<CloudinaryContext cloudName="your-cloud-name">
<Image publicId="img" alt="profile">
</Image>
</CloudinaryContext>
Then, we will create a function that generates a random number for each image. This function is assigned to the index state variable and is updated every time we click on the button. We also need to make sure the random number generated is not higher than the data length in Data.js
.
const [index, setIndex] = useState(0);
const {img} = memes[index];
const checkNumber = (number) => {
if (number > memes.length - 1){
return 0
}
if (number < 0){
return memes.length - 1
}
return number;
}
const randomMeme = () =>{
let randomNumber = Math.floor(Math.random() * memes.length);
if(randomNumber === index){
randomNumber = index + 1;
}
setIndex(checkNumber(randomMeme));
}
Setting up the Auth0 React SDK
Configuring the Auth0Provider
component
Next, we will need to build a feature to prevent unauthorized access to the app.
Create a .env
file to store the Client ID and Domain stated earlier on, then create another file.
#.env
REACT_APP_AUTH0_DOMAIN = THE-DOMAIN-NAME
REACT_APP_AUTH0_CLIENT_ID = THE-CLIENT-ID
Then, install DotEnv using the command:
npm install dotenv
Then in our app, require and configure the package like this:
require('dotenv').config()
The DotEnv npm package automatically loads environment variables from a .env
file into the process.env
object.
The Auth0Provider
component is imported from the @auth0/auth0-react
SDK library to store the authentication state of our users and the state of the SDK — whether Auth0 is ready to use or not.
Next, we will wrap our root component, such as App
in the index.js
file to integrate Auth0 with our React app:
#index.js
import React from "react";
import ReactDOM from "react-dom";
import App from "./App";
import { Auth0Provider } from "@auth0/auth0-react";
require("dotenv").config();
const domain = process.env.REACT_APP_AUTH0_DOMAIN;
const clientId = process.env.REACT_APP_AUTH0_CLIENT_ID;
ReactDOM.render(
<Auth0Provider
domain={domain}
clientId={clientId}
redirectUri={window.location.origin}
>
<App />
</Auth0Provider>,
document.getElementById("root")
);
User Authentication
Create a login-button.js
file to handle the log in feature of the app. This makes use of loginWithRedirect()
method which prompts a user to authenticate before the user can access the app. If the user does not have a Auth0 account, a sign up option is made available by Auth0 React SDK.
import React from "react";
const LoginButton = ({ loginWithRedirect }) => {
return (
<button className="login" onClick={() => loginWithRedirect()}>
Log In
</button>
);
};
export default LoginButton;
We also need a log out feature, create a logout-button.js
file which makes use of logout()
method which clears the application session and redirects a user to the log in page.
import React from "react";
const LogoutButton = ({ logout }) => {
return (
<button className="logout" onClick={() => logout()}>
Log Out
</button>
);
};
export default LogoutButton;
Finally, we will use conditional rendering in the App.js
to show the app when Auth0 has authenticated the user and display an error saying "Log in to gain access to the application" when it has not.
Video
Conclusion
This tutorial covered the most common authentication use case for a React application. It shows that with the help of Auth0, we don't need to be an expert on identity protocols to understand how to secure a web application.
For references, check out:
Content created for the Hackmamba Jamstack Content Hackathon with Auth0 and Cloudinary.