Building a Social Media Preview App with Cloudinary and Auth0

Building a Social Media Preview App with Cloudinary and Auth0

Learn how to use Auth0 and Cloudinary to build an Open Graph Tag Generator Web App
2nd Posted URL
Action Items
Next Action Date
Sep 25, 2021
Posted URL
Published Date
Sep 25, 2021


Authentication and File Storage are common features that developers think about while working on a project. Cloudinary is a service that makes media management easy to integrate for web and mobile developers. Auth0 provides authentication and authorization services that are built into applications. Using these tools avoids the cost, time, and risk of building your own solution.
In this tutorial, we are going to build a real-world application that integrates with Auth0 and Cloudinary.

What We'll Be Building

One of the major reasons for creating content on the internet is to share it with others which often would be via social media. When sharing that URL link depending on the site shared it would most likely use rich previews to show more information about the site. The Open Graph Protocol was developed To standardize the display of link previews and other metadata within a webpage. You can read more about it in Colby's article here.
In this tutorial, we will build a Site Previewer App that displays link previews for social media sites and displays the page metadata.
notion image
You can find the Source Code of the project on Github and Live Environment on Codesandbox


  • Basic understanding of Javascript
  • Basic knowledge of React and React Hooks
  • The Latest version of Nodejs installed on your machine
  • the Latest version of React
  • An Cloudinary account.
  • An Auth0 Account

Step 1. Set up the Project

  1. We will be using TailwindCSS as our CSS Framework. Setup a New Create React App Project with TailwindCSS using this guide from the official Tailwind Docs. If during the installation of Tailwind Libraries your terminal shows a no matches found: postcss@^7 error then install using quotes.
    1. npm install -D "tailwindcss@npm:@tailwindcss/postcss7-compat" "postcss@^7" "autoprefixer@^9"
  1. Once you've completed setting up above. Replace your App.js code to below
//App.js function App() { return ( <div> <h1 className="text-9xl font-bold text-yellow-400">Hello World!</h1> </div> ); } export default App;
You should be getting this screen once you load http://localhost:3000.
notion image
  1. Install @tailwindcss/forms library and add it to your tailwind.config.js plugins array. This will be helpful in styling form elements through TailwindCSS.
npm install @tailwindcss/forms
//tailwind.config.js module.exports = { ... plugins: [require('@tailwindcss/forms')], };

Step 2. Setup Authentication with Auth0 and Views

  • Sign Up/Login to Auth0. You can sign up here . Create an Application. Once Logged in Navigate to your application and copy your Domain and Client ID information.
    • notion image
  • In your project create an .env.local file with the following values. Insert your Copied Client ID & Domain in this file.
  • Install the @auth0/auth0-react npm package from Auth0 for React.
npm install @auth0/auth0-react
  • In order to manage Authentication State within the Application the Auth0 React SDK uses React Context. We can configure the Auth0Provider Component from the root component in index.js .
//index.js import { Auth0Provider } from "@auth0/auth0-react"; .... ReactDOM.render( <Auth0Provider domain={process.env.REACT_APP_AUTH_DOMAIN} clientId={process.env.REACT_APP_AUTH_CLIENT_ID} redirectUri={window.location.origin} > <App /> </Auth0Provider>, document.getElementById("root") );
  • Update your App.js to have a basic authentication setup
//App.js import { useAuth0 } from '@auth0/auth0-react'; import './App.css'; function App() { const { loginWithRedirect, logout, isAuthenticated } = useAuth0(); if (isAuthenticated) { return ( <div> <h1 className="text-9xl font-bold text-yellow-400">Logged In !</h1> <button onClick={() => logout()}>Log Out</button> </div> ); } else { return ( <div> <h1 className="text-9xl font-bold text-yellow-400">Hello World!</h1> <button onClick={() => loginWithRedirect()}>Log In</button> </div> ); } } export default App;
You can see we are able to pull Authentication State and Login/Logout actions from the useAuth0 hook. We use isAuthenticated to switch between showing Content that is Authenticated and that which isn't. Once you update this you should see the Authentication state changes once we log in and out.
notion image

Step 3. Set up Login and Home UI

  • Add Home UI below returned from when isAuthenticated is false
// App.js if(isAuthenticated){ .... }else{ return( <div className=""> <main className="mx-auto max-w-5xl px-4 sm:mt-12 sm:px-6 md:mt-16 lg:mt-20 lg:px-8 xl:mt-28"> <div className="flex flex-col items-center space-y-4 text-center"> <div className="bg-yellow-300 p-4 rounded-lg shadow-md"> <svg class="text-yellow-700 w-20 h-20" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" > <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3.055 11H5a2 2 0 012 2v1a2 2 0 002 2 2 2 0 012 2v2.945M8 3.935V5.5A2.5 2.5 0 0010.5 8h.5a2 2 0 012 2 2 2 0 104 0 2 2 0 012-2h1.064M15 20.488V18a2 2 0 012-2h3.064M21 12a9 9 0 11-18 0 9 9 0 0118 0z" ></path> </svg> </div> <h1 className="text-4xl tracking-tight font-extrabold text-gray-800 sm:text-5xl md:text-6xl"> <span className="block xl:inline">Site Preview</span>{' '} </h1> <p className="mt-3 text-base text-gray-500 sm:mt-5 sm:text-lg sm:max-w-xl sm:mx-auto md:mt-5 md:text-xl lg:mx-0"> Preview and Generate Open Graph meta tags in seconds </p> <div className="mt-5 sm:mt-8 sm:flex sm:justify-center lg:justify-start"> <div className="rounded-md shadow"> <button onClick={() => loginWithRedirect()} className="w-full flex items-center justify-center px-8 py-3 border border-transparent text-base font-medium rounded-md text-white bg-yellow-600 hover:bg-yellow-700 md:py-4 md:text-lg md:px-10" > Log In </button> </div> </div> </div> </main> </div> ); }
  • Create a new file Home.js in the directory src. Setup the Home Component as below
We are also able to fetch the user object from the useAuth0 Hook. We are able to extract the user name and display it once logged in. Your UI should appear like below once your run. We will be defining 3 fields for the Preview Tags which include Title(Less than 60 characters) ,Description(Less than 120 characters) and the Image(URL)
notion image
Let us now work on the PreviewImage and CodeBlock component

Setting up PreviewImage Component

For the preview image component we will create a folder components inside src directory.
  • Add Custom Styling for the Preview Image in App.css.
/* App.css */ .preview { font-size: 12px; font-family: tahoma; border: 1px solid #ccc; color: #555; box-sizing: border-box; text-decoration: none; }
  • Create the Component
// src/components/PreviewImage.js import React from 'react'; const PreviewImage = ({ form }) => { return ( <div class="preview flex flex-col"> <img className="w-full object-cover h-32" src={form.image} alt="some description" /> <div className="px-2 py-2 bg-white"> <h3 className="text-gray-800 font-bold"> {form.title.length === 0 ? `Enter A Title` : form.title} </h3> <p class=""> {form.description.length === 0 ? `Enter A Description` : `${form.description}`} </p> </div> </div> ); }; export default PreviewImage;
  • Import the Component to Home.js
//Home.js import PreviewImage from './components/PreviewImage'; const Home = ()=>{ ... return ( ... <div className="grid grid-cols-2 gap-6"> <form>... <div> {/* Add Preview Image Component Here */} <PreviewImage form={form} /> <div> </div> ) }

Set up CodeBlock Component with Syntax Highlighting

The Last Part of the Home UI setup involves adding a CodeBlock section which displays the tags displayed by completing the form fields entered on the same page. We will display the Metadata Code using Prism which is an elegant syntax highlighter tool.
  • Install prismjs package
npm install prismjs
  • Download you syntax highlighter css from here. For this example we are going to use Okaidia .Remember the download css option is near the bottom of the prismjs download page. Once downloaded place it at the root of the src directory.
import React from 'react'; import Prism from 'prismjs'; import '../prism.css'; const Codeblock = ({ form }) => { const { title, description, image } = form; React.useEffect(() => { Prism.highlightAll(); }, [form]); return ( <div className="flex flex-col mt-4"> <div className="flex justify-between items-center bg-gray-200 p-4 rounded-sm"> <h3 className="text-md text-gray-800 font-semibold">Code</h3> </div> <pre> <code className="language-html"> {` <!-- Replace YOUR_SITE_NAME with the Page/Website URL e.g https://example.com --> <!-- HTML Meta Tags --> <title>${title}</title> <meta name="description" content="${description}"> <!-- Facebook Meta Tags --> <meta property="og:url" content="YOUR_SITE_NAME"> <meta property="og:type" content="website"> <meta property="og:title" content="${title}"> <meta property="og:description" content="${description}"> <meta property="og:image" content="${image}"> <!-- Twitter Meta Tags --> <meta name="twitter:card" content="summary_large_image"> <meta property="twitter:domain" content="YOUR_SITE_NAME"> <meta property="twitter:url" content="YOUR_SITE_NAME"> <meta name="twitter:title" content="${title}"> <meta name="twitter:description" content="${description}"> <meta name="twitter:image" content="${image}"> `} </code> </pre> </div> ); }; export default Codeblock;
  • Import the Codeblock Component to Home.js
//Home.js import Codeblock from './components/Codeblock'; const Home = ()=>{ ... return ( ... <div className="grid grid-cols-2 gap-6"> ... </div> {/* Add Code Block Component Here */} <Codeblock form={form} /> ) }
Once you are done you should have both the PreviewImage and Codeblock rendered properly as below
notion image

Setup Image Uploads with Cloudinary

The application is nearly complete. All we are missing now is adding an Image Upload feature so that it can populate the final image url to the Codeblock and PreviewImage component.
  • Head over to Cloudinary and create an account or login. Once logged in you can check from your Dashboard to see a summary of Account Details,Resources. Copy the Cloud name you see in the Account Details.
    • notion image
  • Head over to the Settings section by clicking on your profile. Select the Upload Tab. Scroll down until you see the Upload Presets section and click on the Enable unsigned uploading button which allows Unauthenticated uploads which will work for this demo. Copy the Name you get in the Unsigned Mode.
    • notion image
  • Head over back to the project and add Cloudinary's widget script in your index.html.
<script src="//widget.cloudinary.com/global/all.js" type="text/javascript"></script>
  • In your .env.local file add your Copied Cloud Name and Upload Preset value in this file.
  • In your Home.js you can add the following function in the Component together with the onClickHandler to the Upload File button that should fires the same function.
//Home.js .... const uploadWidget = () => { window.cloudinary.openUploadWidget( { cloud_name: process.env.REACT_APP_CLOUDINARY_CLOUD_NAME, upload_preset: process.env.REACT_APP_CLOUDINARY_UPLOAD_PRESET, tags: ['site-preview'], sources: ['local', 'url'], }, function (error, result) { if (error) { return; } console.log('Upload Result is', result); setForm({ ...form, image: result[0].url }); }, ); }; .... return( ... <label className="block text-sm font-medium text-gray-700"> Image </label> <button type="button" onClick={() => uploadWidget()} className="..."> </button> )
This function opens the Cloudinary Widget with the specified cloud name and upload preset. It also adds options for local file upload or url upload. Once successful we update the form with the returned image from the result.


Once done the solution is completed. You now have built a powerful social media link previews generator with Authentication and File Storage. There are more features that can probably be added to the app which include
  • Customising Image Feature Options through the powerful Cloudinary Transformation API . Might need to let the user choose the file format of image, crop, background overlays or even blur.
  • View list of Images Selected depending on Auth0 Account Logged In.
Have any other ideas ? Feel free to clone the project and expand on the capabilities of the app using Cloudinary and Auth0.

Last edited on Tue Jun 06 2023

Hey there 👋

Was anything I wrote confusing, outdated, or incorrect? Please let me know! Just write a few words below and I'll be sure to amend this post with your suggestions.