Working with Cloudinary and Auth0 - Build a meme generator with React

Emmanuel Ugwu - Oct 19 '21 - - Dev Community

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

Running npm start should render an app with an affirmative message on our browser:

React App

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;
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

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>
Enter fullscreen mode Exit fullscreen mode

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));
  }
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

Then, install DotEnv using the command:

npm install dotenv
Enter fullscreen mode Exit fullscreen mode

Then in our app, require and configure the package like this:

require('dotenv').config()
Enter fullscreen mode Exit fullscreen mode

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")
);
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

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.

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .