Thumbnail

How to add authentication in NextJs using the clerk

2024-03-29

||

4 mins read

Welcome to my step-by-step guide on adding authentication to your Next.js application using Clerk! If you're like me, you understand the importance of user authentication in web development but also know the headache of implementing it. That's where the Clerk comes in.

Clerk is a fantastic tool that simplifies adding authentication to your Next.js projects. Whether you're building a simple blog, an e-commerce site, or a complex web application, Clerk has got you covered.

In this guide, I'll walk you through the process of setting up authentication in your Next.js app using Clerk, allowing your users to sign up, log in, and access protected routes with ease. So let's dive in and get started!

Step 1: Creating a Clerk Application

  1. Login to your Clerk dashboard and create a new application. Enter your app name, enable Email and Google options and click Create application.
creating a clerk app in clerk
  1. Copy the environment variables from the Clerk dashboard.

Step 2: Setting Up Your Next.js Project

First things first, make sure you have a NextJs project up and running. If you haven't already set one up, you can easily create a new NextJs app using the following command:

npx create-next-app my-next-app

Replace my-next-app with your preferred project name. select typescript and select yes for the src folder. Once the project is created, navigate into the directory:

cd my-next-app

Step 3: Installing Clerk

Now, let's install Clerk in our Next.js project. Clerk provides a hassle-free way to handle authentication, so you can focus on building your app. Just run this command to get started:

npm install @clerk/nextjs

Step 4: Initial Setup

project structure

The above is the structure of the application.

Include the following environment variables in the .env file:

NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=
CLERK_SECRET_KEY=
NEXT_PUBLIC_CLERK_SIGN_IN_URL=/signin
NEXT_PUBLIC_CLERK_SIGN_UP_URL=/signup
NEXT_PUBLIC_CLERK_AFTER_SIGN_IN_URL=/
NEXT_PUBLIC_CLERK_AFTER_SIGN_UP_URL=/

.env

Step 5: Adding ClerkProvider to the application

ClerkProvider is a component provided by the Clerk authentication library for NextJs, which wraps the entire application and provides authentication context to its children.

In the layout.tsx file of the app directory, import the ClerkProvider from @clerk/nextjs.

import "./globals.css";
import { ClerkProvider } from "@clerk/nextjs";

export default function RootLayout({
  children,
}: Readonly<{
  children: React.ReactNode;
}>) {
  return (
    <ClerkProvider>
      <html lang="en">
        <body>{children}</body>
      </html>
    </ClerkProvider>
  );
}

src/app/layout.tsx

Step 6: Adding Authentication

Now that Clerk is installed and integrated into your application, you have the flexibility to determine which pages remain accessible to the public and which require authentication for access. Create a middleware.ts file within the src/ directory.

import { authMiddleware } from "@clerk/nextjs";

export default authMiddleware({
  publicRoutes: ["/"],
});

export const config = {
  matcher: ["/((?!.+\\.[\\w]+$|_next).*)", "/(api|trpc)(.*)"],
};

src/middleware.ts

The authMiddleware() function facilitates authentication processes and restricts entry to routes for visitors who are not logged in. In Next.js, middleware functions operate exclusively on routes designated with matcher().

Step 7: adding sign-in and signup page

The clerk has prebuilt components that we can use to handle the signing and signup easily. In the page.tsx of signin folder add the following code.

import React from "react";
import { SignIn } from "@clerk/nextjs";
import { auth } from "@clerk/nextjs";
import { redirect } from "next/navigation";

export default function Page() {
  const { userId } = auth();
  if (userId) {
    redirect("/");
  }
  return (
    <div className="w-full h-full min-h-screen flex justify-center items-center">
      <SignIn />
    </div>
  );
}

src/app/signin/[[...sign-in]]/page.tsx

The SignIn component is a prebuilt component that is used to handle the signin inside our app. In the page.tsx of the signup folder add the following code.

import React from "react";
import { SignUp } from "@clerk/nextjs";
import { auth } from "@clerk/nextjs";
import { redirect } from "next/navigation";

export default function Page() {
  const { userId } = auth();
  if (userId) {
    redirect("/");
  }
  return (
    <div className="w-full h-full min-h-screen flex justify-center items-center">
      <SignUp />
    </div>
  );
}

src/app/signup/[[...sign-up]]/page.tsx

Step 8: Adding the signout Option

In page.tsx of the app directory add the following code.

import { SignOutButton, auth, currentUser } from "@clerk/nextjs";
import Link from "next/link";

export default async function Home() {
  const { userId } = auth();
  let user;
  if (userId) {
    user = await currentUser();
  }
  return (
    <div>
      <header>
        <nav
          className="flex items-center justify-between p-6 lg:px-8 h-20 border border-t-0 border-x-0 border-b-gray-600"
          aria-label="Global"
        >
          <div className="flex lg:flex-1">
            <a href="/" className="-m-1.5 text-2xl p-1.5">
              clerk-next
            </a>
          </div>
          {userId && (
            <div className="bg-blue-500 hover:bg-blue-400 rounded px-2 py-1">
              <SignOutButton />
            </div>
          )}
        </nav>
      </header>
      <div className="flex min-h-screen items-center justify-center">
        {userId ? (
          <h1 className="text-2xl -mt-36 font-bold">
            Hello {user?.firstName} {user?.lastName}
          </h1>
        ) : (
          <div className="flex flex-col justify-center items-center -mt-36 space-y-3">
            <h1 className="text-2xl font-bold mb-5">Login</h1>
            <Link
              className="bg-blue-600 px-3 py-2 text-lg  font-semibold rounded"
              href={"/signin"}
            >
              signin
            </Link>
          </div>
        )}
      </div>
    </div>
  );
}

src/app/page.tsx

The auth() function retrieves the userId of the user if they are logged in. Meanwhile, the currentUser() function fetches user details such as their first name and last name. Additionally, the SignOutButton component manages the signout functionality.

You can find the source code here.