Building A User Gallery with Auth0, Cloudinary and React

Seun Taiwo - Oct 16 '21 - - Dev Community

We’ve all had our fair share of battling with authentication and authorization as developers. The case seems to be worse for frontend developers who don’t know how to spin up a server and can become hectic for most.

Enter Auth0, a tool that helps you integrate numerous authentication methods like Facebook, Twitter, Github, Microsoft, etc seamlessly into you frontend application. It can also be used on the backend as well.

Cloudinary, on the other hand, is a SaaS company that allows us to upload images and videos in a very easy way by providing us with an Upload Widget.

Content

  • Creating your Auth0 account and setting it up with the different authentication methods.
  • Setting up Cloudinary.
  • Tying it all together in our React App.

Prerequisites

  • You need to have a working understanding of Javascript, React and Express.
  • You must have Node installed.

Setting up Auth0

Head to the Auth0 Signup page. Select the Personal Account Type and leave the ‘I need advanced settings’ unchecked. Verify your account from your email once you’re done.

Auth0 signup page

On clicking next, you’d arrive on your Auth0 Dashboard. Click Applications to create one as we’ll need it to enable the Authentication for our app.

Clicking applications tab

Click on Create Application and a modal will pop up. Fill in your App Name and select Single Page Web Applications since we’re building in React.

Creating the application

After the App has been created, you’ll be asked to select which particular framework you’d be using. You can go ahead and select React. You’ll then be redirected to a page telling you how to set Auth0 up with React but we’d still go through it.

We need to get our Domain and Client ID so slide over to the Settings tab, copy them and paste them somewhere as we’d be needing them later.

Copying the Domain and Client ID

You also need to set Token Endpoint Authentication Method to None and set the Application Type to either SPA.

Finally, we have to set our Callback URL, Logout URL and Allowed Web Origins.

  • Callback URL - It’s simply the URL that the user gets redirected to upon successful login.
  • Logout URL - Like the above, it’s the URL the user gets redirected upon logging out. It must be specified in the logOut parameters also. ( More on this later in the article)
  • Allowed Web Origins - We need to add the URL of our app here once again to enable Auth0 refresh its tokens.

For all, we can simply use our URL as http://localhost:3000 since we’re only testing locally. If you’re deploying it, just replace the URL with the URL of the deployed app.

Now, to set up our different authentication methods, click Social under the Authentication dropdown.

Heading to the social tab

By default, Google OAuth would be enabled for your app but with Development Keys. If the app is to be used in Production, be sure to change it to Production keys before deploying.

We’re going to be adding GitHub and Facebook as our possible sign-in options. Click on the Create Connection button and select GitHub.

Selecting the social connections

We need to get our Github App’s Client ID and Client Secret so open a new tab and head over here and go to the OAuth Apps tab. Click the New OAuth App button and fill in the details.

Registering your Github OAuth App

Application Name - Fill in anything of your choice.
Homepage URL - https://[YOUR_DOMAIN]
Authorization Callback URL - https://[YOUR_DOMAIN]/login/callback

Where YOUR_DOMAIN is the domain we got from Auth0 when setting up our app. Click Register Application, Generate your Client Secret on the next page and copy both your Client Secret and Client ID.

Head back to the Auth0 tab and paste them in their respective fields. Under Attributes, check ‘Email Address’ as we’ll be needing it.
On the next page, turn on the social connection for your application so you can make use of it.

Turning on social connection for the application

You can click on Try Connection to test it out. If it doesn’t work, try and go back and retrace where the mistake came from.

Go to the Social Connections page once again and Create a new Connection. This time, select Facebook.

Open a new tab, head over here and login to your Facebook account.
Click on My Apps in the navbar. The App Type should be Consumer
Enter the name you want to give the app and submit.

On your dashboard, Click the Set Up button on Facebook Login

Facebook dashboard

Click Web on the next page and enter your URL as https://[YOUR_DOMAIN]/login/callback. Hit Save and and go into the Settings Tab

Settings tab

As you can see atop the page, we need to get Advanced Access. Click on the Get Advanced Access Link. Click on Get Advanced for public_profile and email.

Getting advanced access

The page should look something like this when you’re done.

Page after getting advanced access

Head over to the Basic Tab of the Settings dropdown, copy your App ID as well as your App Secret and paste them in their respective fields on the Auth0 Facebook Connection Page. Tick the Checkbox of the email once again and Create the connection. Connect it to your App once again and we’re good to go.

Your social connections page should look something like this at this point.

Social Connections Page


Setting Up Cloudinary

Signup for your Cloudinary account here and verify your email.

On getting to your account dashboard, all keys you need are displayed atop the page.

Cloudinary dashboard

You can leave the tab open cause we’re going to need some details later in the article. Click the Gear Icon on the navbar to go to the settings page. Go to the Upload tab and scroll down to upload presets. Click Enable unsigned uploading and an unsigned upload preset will automatically be added. Copy the preset name as we’ll need it later.

Cloudinary upload presets

Tying it all together with our React App

Our React app is gonna be a user gallery where users come, sign in with Auth0 and their images get stored in the Cloudinary Account we’ve created. We need to fetch all images a user has uploaded also and to do this we need to pass our Cloudinary API Secret. Bear in mind that fetching an image through its url requires no authentication. Fetching the list of images of a user on the client side would be bad as attackers can go through our source code and figure out our API Secret at which point they’d have total access over our account. For this reason, we need to spin up a server.

Spinning up the server

  • Head over to this repo and clone it locally.
  • You need a .env file to store your keys so create one in the folder like so:
   API_KEY="YOUR_API_KEY"
   API_SECRET="YOUR_API_SECRET"
   CLOUD_NAME="YOUR_CLOUD_NAME"
Enter fullscreen mode Exit fullscreen mode
  • Run the command below to install all packages required
   yarn
Enter fullscreen mode Exit fullscreen mode

or

    npm install
Enter fullscreen mode Exit fullscreen mode

depending on your package manager.

  • Run this in your terminal to start the server.
   node app.js
Enter fullscreen mode Exit fullscreen mode

You should get a response saying ‘Server connected on PORT 3001’

Spinning up the React App

  • Clone the React App here.

  • Run the command below to install all packages required

   yarn
Enter fullscreen mode Exit fullscreen mode

or

    npm install
Enter fullscreen mode Exit fullscreen mode

depending on your package manager.

  • Open up the index.js file.
import React from "react";
import ReactDOM from "react-dom";
import "./index.css";
import App from "./App";
import { Auth0Provider } from "@auth0/auth0-react";
//import reportWebVitals from './reportWebVitals';
ReactDOM.render(
  <Auth0Provider
    domain={process.env.REACT_APP_DOMAIN}
    clientId={process.env.REACT_APP_CLIENT_ID}
    redirectUri="http://localhost:3000"
  >
    <React.StrictMode>
      <App />
    </React.StrictMode>
  </Auth0Provider>,
  document.getElementById("root")
);  
Enter fullscreen mode Exit fullscreen mode

To use Auth0 with React, we had to install the package ‘@auth0/auth0-react’. We’re simply setting up Auth0 with our app by passing it our Domain and Client ID which we got earlier. The redirectUri is the URL we’d like to redirect our users after they’re authenticated.

  • Open up the login.component.jsx file
import React from "react";
import { useAuth0 } from "@auth0/auth0-react";
import "./login.css";
const LoginButton = () => {
  const { loginWithPopup, loginWithRedirect } = useAuth0();
  return <button onClick={() => loginWithPopup()}>Log In</button>;
};
const Login = () => {
  return (
    <div className="login container">
      <LoginButton />
    </div>
  );
};
export default Login;  
Enter fullscreen mode Exit fullscreen mode

Here, we’re using the useAuth0 hook to get our login functions. We have loginWithPopup and loginWithRedirect which logs the user in through a popup and through redirecting to another page respectively as their name imply.

  • Finally, we have the home.component.jsx file
import React, { useEffect, useRef, useState } from "react";
import { useAuth0 } from "@auth0/auth0-react";
import axios from "axios";
import "./home.css";
import Loader from "./../utils/loader.component";
const LogoutButton = () => {
  const { logout } = useAuth0();
  return (
    <button onClick={() => logout({ returnTo: window.location.origin })}>
      Log Out
    </button>
  );
};
const Home = () => {
  const { user } = useAuth0();
  const btnRef = useRef(null);
  const [images, setImages] = useState([]);
  console.log(user);
  const fetchImages = async () => {
    let { data } = await axios.get("http://localhost:3001/images");
    setImages((images) => [...images, ...data]);
  };
  const setUploadWidget = () => {
    var myWidget = window.cloudinary.createUploadWidget(
      {
        cloudName: process.env.REACT_APP_CLOUD_NAME,
        uploadPreset: process.env.REACT_APP_UPLOAD_PRESET,
        folder: user.email,
        tags: [user.email],
      },
      (error, result) => {
        if (!error && result && result.event === "success") {
          setImages((prevImages) => [...prevImages, result.info.secure_url]);
        }
      }
    );
    btnRef.current.addEventListener(
      "click",
      function () {
        myWidget.open();
      },
      false
    );
  };
  useEffect(() => {
    setUploadWidget();
    fetchImages();
  }, []);
  return (
    <div className="home">
      <header>
        <img src={user.picture} alt="" />
        <h2>Welcome, {user.name}</h2>
        <LogoutButton />
      </header>
      <button ref={btnRef} className="cloudinary-button">
        Upload files
      </button>
      <section>
        {images.length ? (
          images.map((image, index) => (
            <a
              href={image}
              key={index}
              target="_blank"
              rel="noopener noreferrer"
            >
              <img src={image} alt="Ronaldo" />
            </a>
          ))
        ) : (
          <Loader home />
        )}
      </section>
    </div>
  );
};
export default Home;  
Enter fullscreen mode Exit fullscreen mode

First, we create our LogoutButton component which is based on the logout function gotten from the useAuth0 hook once again.

In our Home Component which is the main component, we have two main functions, the fetchImages function, which fetch all images of the logged in user and the setUploadWidget function which sets the upload widget to open up when the upload button is pressed.
We then call both functions in a useEffect to ensure they are both called every time the page loads.

In the App.js file, we use react-router-dom to enable different routes. We also create custom components PrivateRoute and PublicRoute to help redirect users who are not logged in to the login page and vice versa.

We also need another .env file for our environment variables.

    REACT_APP_DOMAIN="YOUR_AUTH0_DOMAIN"
    REACT_APP_CLIENT_ID="YOUR_AUTH0_CLIENT_ID"
    REACT_APP_CLOUD_NAME="YOUR_CLOUDINARY_CLOUD_NAME"
  REACT_APP_UPLOAD_PRESET="YOUR_UNSIGNED_CLOUDINARY_UPLOAD_PRESET"
Enter fullscreen mode Exit fullscreen mode

You can then go ahead and run

    yarn start
Enter fullscreen mode Exit fullscreen mode

or

    npm start
Enter fullscreen mode Exit fullscreen mode

to launch the project and everything should be working smoothly.

If you have any issues or want to contact me, you can reach me at lorddro1532@gmail.com or on Twitter at @the_dro_.

Content created for the Hackmamba Jamstack Content Hackathon with Auth0 and Cloudinary.

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