Logo

dev-resources.site

for different kinds of informations.

Implementing Authentication with Clerk in Next.js

Published at
10/14/2024
Categories
nextjs
clerk
authentication
reacthookform
Author
Atsushi Miyamoto
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
  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>
     )
   }
  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)(.*)',
     ],
   }

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 />
}

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)
   }
  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>
     )
   }
  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')} />
       </>
     )
   }
  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>
     )
   }

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

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

Featured ones: