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:

Step 1: Create a New React App With Vite

Step 2: Install and Configure Tailwindcss

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

@tailwind base;
@tailwind components;
@tailwind utilities;

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;

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

VITE_CLERK_PUBLISHABLE_KEY=pk_test_w29vZmJjYXNpbmctY29ucmF0ZS0xMy5jbGVyay5hY2NvdW50cy5kZXYkRg 
This is a fake publishable key.

Step 4: Integrate Clerk Into 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.

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;

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;

import React from 'react';
import Header from './Header';

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

export default Layout;

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.

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;

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;

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

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;

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 { SignedIn, SignedOut, RedirectToSignIn } from '@clerk/clerk-react';

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;

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.