Implementing Authentication with Clerk in Next.js

atsushii

Atsushi Miyamoto

Posted on October 14, 2024

Implementing Authentication with Clerk in Next.js

Introduction

Hello! I'm Atsushi, a cloud engineer working at a SaaS company in Tokyo. Recently, I implemented authentication features for my personal AI chatbot project using Clerk, an authentication service. I'd like to share the insights I gained from this experience.

What is Clerk?

Clerk is a service that provides embeddable UI components, APIs, and an administrative dashboard for user authentication and management. It supports frontend frameworks like Next.js, React, and Remix.

In addition to authentication features, Clerk offers UI components that make it easy to implement sign-in and login screens. It also integrates with services like Supabase and Firebase.

Account Creation

To get started with Clerk:

  1. Sign up at Clerk's website by clicking the "Get started" button.
  2. After creating an account, set up your application by providing a name and clicking "Create application".

Implementing Authentication Screens

Clerk provides UI components that make it easy to implement authentication screens. This guide focuses on implementation with Next.js using the App Router.

Prerequisites

  1. Set environment variables in .env.local:
   NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=xxx
   CLERK_SECRET_KEY=xxx
Enter fullscreen mode Exit fullscreen mode
  1. Set up the Clerk Provider in app/layout.tsx:
   import { ClerkProvider } from '@clerk/nextjs'
   import { jaJP } from '@clerk/localizations'

   export default function RootLayout({
     children,
   }: {
     children: React.ReactNode
   }) {
     return (
       <ClerkProvider localization={jaJP}>
         <html>
           <body>
             <main>{children}</main>
           </body>
         </html>
       </ClerkProvider>
     )
   }
Enter fullscreen mode Exit fullscreen mode
  1. Implement Middleware in middleware.ts:
   import { clerkMiddleware } from '@clerk/nextjs/server'

   export default clerkMiddleware()

   export const config = {
     matcher: [
       '/((?!_next|[^?]*\\.(?:html?|css|js(?!on)|jpe?g|webp|png|gif|svg|ttf|woff2?|ico|csv|docx?|xlsx?|zip|webmanifest)).*)',
       '/(api|trpc)(.*)',
     ],
   }
Enter fullscreen mode Exit fullscreen mode

Using Standard Components

Clerk provides ready-to-use components like <SignUp /> and <SignIn /> that can be easily implemented:

import { SignUp } from '@clerk/nextjs'
export default function Page() {
  return <SignUp />
}
Enter fullscreen mode Exit fullscreen mode

Custom Implementation with React Hook Form

For more control over the form, you can use React Hook Form with Clerk's helpers:

  1. Create a custom hook (useSignInForm):
   import { useSignIn } from '@clerk/nextjs'
   import { zodResolver } from '@hookform/resolvers/zod'
   import { useForm } from 'react-hook-form'
   import { z } from 'zod'

   // ... (schema and type definitions)

   export const useSignInForm = () => {
     const { isLoaded, setActive, signIn } = useSignIn()
     // ... (form setup and submit handler)
   }
Enter fullscreen mode Exit fullscreen mode
  1. Create a Form Provider:
   import { useSignInForm } from '@/hooks/sign-in/use-sign-in'
   import { FormProvider } from 'react-hook-form'

   const SignInFormProvider = ({ children }: Props) => {
     const { methods, onHandleSubmit, loading } = useSignInForm()

     return (
       <FormProvider {...methods}>
         <form onSubmit={onHandleSubmit}>{children}</form>
       </FormProvider>
     )
   }
Enter fullscreen mode Exit fullscreen mode
  1. Create the Form component:
   import { useFormContext } from 'react-hook-form'

   const LoginForm = () => {
     const {
       register,
       formState: { errors },
     } = useFormContext()
     return (
       <>
         <h2>Login</h2>
         <input {...register('email')} />
         <input {...register('password')} />
       </>
     )
   }
Enter fullscreen mode Exit fullscreen mode
  1. Implement the login page:
   import SignInFormProvider from '@/components/forms/sign-in/form-provider'
   import LoginForm from '@/components/forms/sign-in/login-form'

   const SignInPage = () => {
     return (
       <SignInFormProvider>
         <LoginForm />
         <button type="submit">Login</button>
       </SignInFormProvider>
     )
   }
Enter fullscreen mode Exit fullscreen mode

Retrieving Authentication Information

To get the user ID after sign-up:

import { currentUser } from '@clerk/nextjs/server'
const user = await currentUser()
const id = user.id
Enter fullscreen mode Exit fullscreen mode

Conclusion

Clerk significantly simplifies the implementation of authentication features.
Its flexibility allows for easy integration with popular tools like React Hook Form and Zod.
However, for Next.js projects, alternatives like Auth.js or Supabase's built-in authentication should also be considered depending on the use case.

References

💖 💪 🙅 🚩
atsushii
Atsushi Miyamoto

Posted on October 14, 2024

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related