paint-brush
How to Secure User Authentication in React With Clerkby@Temmarie
791 reads
791 reads

How to Secure User Authentication in React With Clerk

by Grace Tamara EkunolaSeptember 17th, 2024
Read on Terminal Reader
Read this story w/o Javascript
tldt arrow

Too Long; Didn't Read

Authentication in React can be complicated for beginners. [Clerk] is a user management platform that simplifies the authentication process. It offers features like user profiles, sessions, passwordless login, Multi-factor authentication, Email and SMS OTP. In this tutorial, we will build a simple authentication app using React. And we'll style it using Tailwindcss.
featured image - How to Secure User Authentication in React With Clerk
Grace Tamara Ekunola HackerNoon profile picture



User authentication is an integral part of any application—whether a web app, mobile app, or an entire organization's infrastructure. It ensures that only authorized users can access specific resources, data, or services. It helps to prevent data breaches, unauthorized access, and other security threats.


Authentication in React, while straightforward for experienced developers, can be complicated for beginners. This also depends on the features the developers want to include in their authentication, like passwordless login (Google, Facebook, Apple, etc.), multi-factor authentication, and user roles. The more features included, the more detailed it becomes. That is where Clerk comes in, providing a simple solution without the hassle of building from scratch.

What is Clerk?

Clerk is a user management platform that simplifies the authentication process and offers everything needed for user authentication and management, including features like user profiles, sessions, passwordless login, Multi-factor authentication, Email and SMS OTP and many more.


Clerk also supports a variety of frameworks (Frontend and Backend) and integrations like NextJs, React, Node/Express, Ruby on Rails, Firebase, Supabase, Hasura, Google Analytics and others.


In this tutorial, we will build a simple authentication app using React. And we'll style it using Tailwindcss.


Beginner developers should learn to build user authentication from scratch to understand the process and how to implement it effectively.

Prerequisites

Before starting this tutorial, you should have a good understanding of the fundamentals of JavaScript and React. Additionally, you must have the following software installed on your computer:


  • Node.js: Install Node.js to manage the asset pipeline and run JavaScript code.
  • npm or yarn (package manager)
  • A code editor, like VS Code
  • A browser like Google Chrome


Step 1: Create a New React App With Vite

  • To create a new React app, navigate to your preferred directory, and run npm create vite@latest clerkapp.


  • Select your preferred framework and variant. In this case, I'll be using React and JavaScript.


  • This will create a new React application called clerkapp. Open this directory in your preferred text editor.


  • To install the dependencies, run npm install.


  • Then launch the app: npm run dev.


  • Open http://localhost:5173/ in your browser to access the Vite welcome page.

Step 2: Install and Configure Tailwindcss

  • To install Tailwindcss, run: npm install -D tailwindcss postcss autoprefixer


  • Generate the config files: npx tailwindcss init -p


  • Update the content field in the tailwind.config.js
/** @type {import('tailwindcss').Config} */
export default {
  content: [
    "./index.html",
    "./src/**/*.{js,ts,jsx,tsx}",
  ],
  theme: {
    extend: {},
  },
  plugins: [],
}


  • In src/index.css, remove the boilerplate designs and add:
@tailwind base;
@tailwind components;
@tailwind utilities;


  • Navigate to App.jsx , and remove the boilerplate code and replace it with:
import React from 'react';

const App = () => {
  return (
    <div className="min-h-screen bg-purple-300 flex items-center justify-center">
 <h1 className="text-indigo-400 font-bold">Hello, TailwindCSS!</h1>
 </div>
 );
};

export default App;


  • Restart the server, and see the new changes.


Tailwindcss has been successfully integrated



Note: Sometimes, Tailwindcss may not take effect immediately. In such a case, you can either uninstall and then reinstall Tailwindcss or regenerate the config files: npx tailwindcss init -p


Step 3: Install and Configure Clerk for Authentication

  • Sign up to create a Clerk account, or sign in if you already have one. If the clerk's website does not open, use a secure VPN to access the website.


  • Once logged in, you'll see a page that asks you to build your sign-in. This page is basically for you to configure your application name as well as sign-in options which can all be later changed in your dashboard if need be.


  • For this article, we'll settle with the basics. I'll call the application ClerkApp and use Email, Username, and Google as my sign-in options. Feel free to customize it to your preferred sign-in options.


  • Once you create the application, you'll be redirected to your dashboard where you can proceed to choose your preferred framework, in this case, React.


  • Navigate to the terminal, and install Clerk for React. npm install @clerk/clerk-react.


  • Create a .env.local file in your root folder to set up your environment variables, and add your API key. It should look like:


VITE_CLERK_PUBLISHABLE_KEY=pk_test_w29vZmJjYXNpbmctY29ucmF0ZS0xMy5jbGVyay5hY2NvdW50cy5kZXYkRg 
This is a fake publishable key.


Application Setup on Clerk




Step 4: Integrate Clerk Into the App

  • Navigate to the main.jsx file to import your Clerk publishable key, and wrap your app with Clerk's ClerkProvider component to enable authentication features throughout the app.
import React from 'react';
import ReactDOM from 'react-dom/client'
import App from './App';
import './index.css';
import { ClerkProvider } from '@clerk/clerk-react'; 

const PUBLISHABLE_KEY = import.meta.env.VITE_CLERK_PUBLISHABLE_KEY;

if (!PUBLISHABLE_KEY) {
  throw new Error('Clerk publishable key is missing.');
}

ReactDOM.createRoot(document.getElementById('root')).render(
  <ClerkProvider publishableKey={PUBLISHABLE_KEY}>
    <App />
  </ClerkProvider>
);

Step 5: Create Navigation Components.

In this step, we'll create the app navigation components: the Header, the Layout, the Homepage and the Dashboard.


  • Install react-router-dom to enable page navigation. npm install react-router-dom


  • In the src folder, create a new components folder and cd into it. This is where we'll store all of our authentication components and layouts.


  • In the components folder, create a new file called Header.jsx .Add the following code:
import React from 'react';
import { Link } from 'react-router-dom';
import { useUser, useClerk } from '@clerk/clerk-react';

const Header = () => {
  const { user } = useUser();
  const { signOut } = useClerk();

  return (
    <nav className="flex items-center justify-between px-6 py-4 mb-5 bg-black">
      <div className="flex items-center">
        <Link to="/">
          <div className="text-lg font-bold text-purple-300 uppercase">
            ClerkApp
          </div>
        </Link>
      </div>
      <div className="flex items-center text-purple-200">
        {!user && (
          <>
            <Link
              to="/sign-in"
              className="text-purple-300 hover:text-purple-400 mr-4"
            >
              Sign In
            </Link>
            <Link
              to="/sign-up"
              className="text-purple-300 hover:text-purple-400 mr-4"
            >
              Sign Up
            </Link>
          </>
        )}
        {user && (
          <>
            <Link
              to="/profile"
              className="text-purple-300 hover:text-purple-400 mr-4"
            >
              Profile
            </Link>
            <button
              onClick={() => signOut()}
              className="text-purple-300 hover:text-purple-400"
            >
              Sign Out
            </button>
          </>
        )}
      </div>
    </nav>
  );
};

export default Header;



  • Create a new file, and call it Dashboard.jsx. This is the page users will see once signed in. It'll include a small welcome message with the username. We'll use the useUser hook from the Clerk library to display the username.
import React from 'react';
import { useUser } from '@clerk/clerk-react';


const Dashboard = () => {
  
  const { user } = useUser();
  
  return (
    <div className="min-h-screen bg-purple-50 flex flex-col items-center justify-center">
      <div className="bg-white shadow-lg rounded-xl p-10 w-full max-w-lg">
        <h1 className="text-4xl font-extrabold text-purple-600 mb-6">Dashboard</h1>
        <p className="text-lg text-gray-700 mb-6 font-bold text-purple-800 capitalize">
          Hello {user ? user.username : user.fisrtName}!
        </p>
        <p> Welcome to Clerk App, where you can manage your User Authentication with ease.</p>
      </div>
    </div>
  );
};

export default Dashboard;


  • Create a new file, and call it Layout.jsx. This is a wrapper component for the app to ensure the Header component is consistently displayed across various parts of the app. You are free to customize it to your needs.
import React from 'react';
import Header from './Header';

const Layout = ({ children }) => (
  <div className="layout-container">
    <Header />
    <main>{children}</main>
  </div>
);

export default Layout;


  • Create a new file called HomePage.jsx, this will be the app's landing page. This page can be accessed by both authenticated and unauthenticated users.
import React from 'react';

const HomePage = () => {
  return (
    <div className="flex flex-col items-center justify-center min-h-screen bg-gray-100 p-4">
      <h1 className="text-4xl font-bold text-purple-600 mb-4">Welcome to Clerk App</h1>
      <p className="text-lg text-gray-700 mb-2">This is a public homepage that anyone can view.</p>
      <p className="text-md text-gray-600">Please sign in to access more features.</p>
    </div>
  );
};

export default HomePage;

Step 6: Create Authentication Components.

In this step, we'll create all the components involved in user authentication. The Sign-in, the Sign-up, and Profile components.


  • In the components folder, create a new SignIn.jsx file for the sign-in component.
import React from 'react';
import { SignIn } from '@clerk/clerk-react';

const SignInPage = () => (
  <div className="flex items-center justify-center min-h-screen">
    <div className="text-center">
      <SignIn path="/sign-in" routing="path" />
    </div>
  </div>
);

export default SignInPage;


  • Create a new SignUp.jsx file for the sign-up component.
import React from 'react';
import { SignUp } from '@clerk/clerk-react';

const SignUpPage = () => (
  <div className="flex items-center justify-center min-h-screen">
    <div className="text-center">
      <SignUp path="/sign-up" routing="path" />
    </div>
  </div>
);

export default SignUpPage;


  • Create a Profile.jsx file for the profile component.
import React from 'react';
import { UserProfile } from '@clerk/clerk-react';

const Profile = () => {
  return (
    <div className="flex items-center justify-center min-h-screen">
      <UserProfile path="/profile" routing="path" />
    </div>
  );
};

export default Profile;

Step 7: Rendering All the Components in App.jsx

  • Navigate to App.jsx, and import and render all the previously created components.
import React from 'react';
import { BrowserRouter as Router, Routes, Route } from 'react-router-dom';
import Dashboard from './components/Dashboard';
import Profile from './components/Profile';
import SignInPage from './components/SignIn';
import SignUpPage from './components/SignUp';
import HomePage from './components/HomePage';
import Layout from './components/Layout';
import './index.css'

const App = () => (
    <Router>
        <Layout>
            <Routes>
                <Route path="/" element={<HomePage />} /> 
                <Route path="/dashboard" element={<Dashboard />} />
                <Route path="/profile" element={<Profile />} />
                <Route path="/sign-in" element={<SignInPage />} />
                <Route path="/sign-up" element={<SignUpPage />} />
            </Routes>
       </Layout>
    </Router>
);

export default App;


  • Restart your server, and look at the changes. You should now have a page with a welcome message and be able to sign up, sign in, sign out, or view your profile.


Homepage



Step 8: Protecting Routes

Now that the authentication is almost complete, we need to ensure that certain routes like Dashboard are restricted to unauthenticated users. To do this, we'll use Clerk's SignedIn, SignedOut and RedirectToSignIn components to handle this.


  • Import the necessary Clerk components and add them to the top of your file.

import { SignedIn, SignedOut, RedirectToSignIn } from '@clerk/clerk-react';


  • Set up public and protected routes: Define the Homepage as a public route since we want it accessible to all users.


  • Wrap all the routes that require authentication (Dashboard and Profile) with the SignedIn component.


  • Use the SignedOut component for public routes like the sign-in and sign-out routes which are accessible to unauthenticated users.


  • Unauthorized access will be redirected to the sign-in page using the Clerk's RedirectToSignIn component.


  • In the App.jsx file, your code should look like this:
import React from 'react';
import { BrowserRouter as Router, Routes, Route } from 'react-router-dom';
import { SignedIn, SignedOut, RedirectToSignIn } from '@clerk/clerk-react';
import Dashboard from './components/Dashboard';
import Profile from './components/Profile';
import SignInPage from './components/SignIn';
import SignUpPage from './components/SignUp';
import HomePage from './components/HomePage';
import Layout from './components/Layout';
import './index.css';

const App = () => {
  return (
    <Router>
      <Layout>
        <Routes>
          {/* HomePage Route */}
          <Route
            path="/"
            element={<HomePage />}
          />
          {/* Dashboard Route */}
          <Route
            path="/dashboard"
            element={
              <SignedIn>
                <Dashboard />
              </SignedIn>
            }
          />
          {/* Profile Route */}
          <Route
            path="/profile"
            element={
              <SignedIn>
                <Profile />
              </SignedIn>
            }
          />
          {/* Sign In Route */}
          <Route
            path="/sign-in"
            element={
              <SignedOut>
                <SignInPage />
              </SignedOut>
            }
          />
          {/* Sign Up Route */}
          <Route
            path="/sign-up"
            element={
              <SignedOut>
                <SignUpPage />
              </SignedOut>
            }
          />
          {/* Redirect unauthenticated to sign-in */}
          <Route
            path="*"
            element={
              <SignedOut>
                <RedirectToSignIn />
              </SignedOut>
            }
          />
        </Routes>
      </Layout>
    </Router>
  );
};

export default App;


The SignedIn component renders its children only if the user is signed In, the SignedOut component renders its children when the user is unauthenticated and the RedirectToSignIn component restricts unauthorized access.

Step 9: Update the Header.jsx

For easy navigation, we'll make some slight changes in the Header.


We want authenticated users to be able to access their dashboard and homepage, so we will use conditional rendering to ensure that the Dashboard link is only visible when a user is signed in.


import React from 'react';
import { Link } from 'react-router-dom';
import { useUser, useClerk } from '@clerk/clerk-react';

const Header = () => {
  const { user } = useUser();
  const { signOut } = useClerk();

  return (
    <nav className="flex items-center justify-between px-6 py-4 mb-5 bg-black">
      <div className="flex items-center">
        <Link to="/">
          <div className="text-lg font-bold text-purple-300 uppercase">
            ClerkApp
          </div>
        </Link>
      </div>
      <div className="flex items-center text-purple-200">
        {!user && (
          <>
            <Link
              to="/sign-in"
              className="text-purple-300 hover:text-purple-400 mr-4 uppercase"
            >
              Sign In
            </Link>
            <Link
              to="/sign-up"
              className="text-purple-300 hover:text-purple-400 mr-4 uppercase"
            >
              Sign Up
            </Link>
          </>
        )}
        {user && (
          <>
            <Link
              to="/dashboard"
              className="text-purple-300 hover:text-purple-400 mr-4"
            >
              Dashboard
            </Link>
            <Link
              to="/profile"
              className="text-purple-300 hover:text-purple-400 mr-4"
            >
              Profile
            </Link>
            <button
              onClick={() => signOut()}
              className="text-purple-300 hover:text-purple-400"
            >
              Sign Out
            </button>
          </>
        )}
      </div>
    </nav>
  );
};

export default Header;


  • You have successfully integrated Clerk and set up user authentication for your application. Restart your development server to review the changes. The app should be fully authenticated.


Authenticated User Homepage

Authenticated User Dashboard



Conclusion

In this tutorial, we used Clerk to add user authentication to our React app. We built an application where users can sign in, sign up, and access protected routes like the Dashboard and Profile. We also integrated TailwindCSS for styling. Additionally, we used conditional rendering in the Header component to improve navigation based on authentication status.


To expand your understanding of Clerk and TailwindCSS, refer to their official documentation for more features and customization options.