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.