How to Set Up NextAuth.js with NextJS 14, App Router, and Typescript

How to Set Up NextAuth.js with NextJS 14, App Router, and Typescript

1.) Puth these in .env.local file

NEXTAUTH_URL="http://localhost:3000" NEXTAUTH_SECRET="DwyqlAMSV********JhaUxW+RtnFuOpdB9LU=". GOOGLE_ID="********" GOOGLE_SECRET="********" GITHUB_ID="*******" GITHUB_SECRET="*******"

2.) Create src/app/api/auth/[…nextauth]/route.ts

import NextAuth, { AuthOptions } from "next-auth"

// Providers
import GoogleProvider from "next-auth/providers/google"
import GithubProvider from "next-auth/providers/github"
import CredentialsProvider from "next-auth/providers/credentials"

import { getUserByEmailAndPassword } from "@/blog_api/user_repo"
import { sha256 } from "@/utils"

export const authOptions: AuthOptions = {
  providers: [
    GithubProvider({
      clientId: process.env.GITHUB_ID!,
      clientSecret: process.env.GITHUB_SECRET!
    }),
    CredentialsProvider({
      name: 'E-Mail and Password',
      // For next-auth to create form inputs for signin
      credentials: {
        email: {
          label: 'E-Mail',
          placeholder: 'E-Mail',
          type: 'text',
        },
        password: {
          label: 'Password',
          type: 'password'
        }
      },
      // If email and password include in the database return user otherwise return null
      async authorize(credentials, req) {
        if (credentials?.email && credentials?.password) {
          try {
            const hashedPassword = await sha256(credentials.password)
            return await getUserByEmailAndPassword(credentials.email, hashedPassword)
          } catch (_) {
            return null
          }
        }

        return null
      }
    })
  ],
  debug: false,
  callbacks: {
    // Add user id to the token
    async jwt({ token, user }) {
        if (user) {
            token.id = user.id
        }

        return token
    },
    // Add user id to the session from the token
    async session({ session, token }) {
        if (session.user) session.user.id = token.id

        return session
    },
    // Always redirect to base url
    async redirect({ url, baseUrl }) {
      return process.env.NEXTAUTH_URL!
    }
  }
}

export const handler = NextAuth(authOptions)

export { handler as GET, handler as POST }

3.) Create SessionProvider Component

'use client'

import { SessionProvider } from "next-auth/react"

export default SessionProvider

4.) Wrap body content with SessionProvider in Root Layout

import type { Metadata } from "next"
import "../../globals.css"
import Header from "./(components)/Header"
import Footer from "./(components)/Footer"
import { getServerSession } from 'next-auth'
import SessionProvider from '@/app/(blog)/blog/(components)/SessionProvider'

export const metadata: Metadata = {
  title: "title",
  description: "description",
};

export default async function RootLayout({
  children
}: Readonly<{
  children: React.ReactNode,
}>) {
  const session = await getServerSession()

  return (
    <html lang="en">
      <body className="dark:bg-black bg-gray-50">
        <SessionProvider session={session}>
          <Header />
          {children}
          <Footer />
        </SessionProvider>
      </body>
    </html>
  );
}

5.) If you need to expand interfaces create next-auth.d.ts

// Expand User (for id, email, password) and JWT (for id) interfaces

import NextAuth from "next-auth"

declare module "next-auth" {
    interface User {
        id: string
        email: string
        password: string
    }
  /**
   * Returned by `useSession`, `getSession` and received as a prop on the `SessionProvider` React Context
   */
  interface Session extends DefaultSession {
    user?: User
  }
}

import { JWT } from "next-auth/jwt"

declare module "next-auth/jwt" {
  /** Returned by the `jwt` callback and `getToken`, when using JWT sessions */
  interface JWT {
    id: string
  }
}

6.) An example of using Server Side getServerSession() method for using Session and Protect routes (Profile Page)

import { routeMap } from "@/app/(admin)/routeMap"
import { getServerSession } from "next-auth"
import { redirect } from "next/navigation"

export default async function ProfilePage() {
    const session = await getServerSession()

    if (!session) {
        redirect(routeMap.blog.users.signin)
    }

    return (
        <div>Profile page</div>
    )
}

7.) An example of using Client Side useSession() method for using Session

'use client'

import { useSession } from 'next-auth/react'
import { routeMap } from '@/app/(admin)/routeMap'
import Image from 'next/image'
import Link from 'next/link'
import { MdAccountCircle, MdAppRegistration, MdLogin, MdLogout } from "react-icons/md"
import { IoPersonCircle } from "react-icons/io5"

export default function UserButton() {
    const { data: session } = useSession()

    return (
        <div className='relative group'>
            {
                session?.user?.image
                    ? <Image
                        width={36}
                        height={36}
                        src={session.user.image}
                        alt="Profil foto"
                        className='rounded-full border-gray-400 border cursor-pointer'
                    />
                    : <IoPersonCircle size={36} className={'dark:text-white'} />
            }
            <div className='absolute hidden w-28 left-[-7rem] top-[-2px] flex-col group-hover:flex bg-gray-300 shadow-xl rounded-md'>
                {!session?.user && <Link
                    href="/api/auth/signin"
                    className='flex justify-between items-center gap-2 p-2 hover:bg-gray-400 cursor-pointer rounded-md'>
                    <span>Sign In</span>
                    <MdLogin />
                </Link>}
                {!session?.user && <Link
                    href={routeMap.blog.users.register.root}
                    className='flex justify-between items-center gap-2 p-2 hover:bg-gray-400 cursor-pointer rounded-md'>
                    <span>Sign Up</span>
                    <MdAppRegistration />
                </Link>}
                {session?.user && <Link
                    href={routeMap.blog.users.profile.root}
                    className='flex justify-between items-center gap-2 p-2 hover:bg-gray-400 cursor-pointer rounded-md'>
                    <span>Profile</span>
                    <MdAccountCircle />
                </Link>}
                {session?.user && <Link
                    href="/api/auth/signout"
                    className='flex justify-between items-center gap-2 p-2 hover:bg-gray-400 cursor-pointer rounded-md'>
                    <span>Sign Out</span>
                    <MdLogout />
                </Link>}
            </div>
        </div>
    )
}

AI Summarize

This article provides a comprehensive guide on setting up authentication in a Next.js application using NextAuth.js. It covers configuring environment variables, creating authentication routes, implementing custom providers like Google and GitHub, and building a session provider component. The guide also includes instructions for wrapping the root layout with session management and demonstrates server-side and client-side methods for accessing user sessions. The article concludes with examples of session-based route protection and a user interface element for authentication actions.