Retrieve session on both server and client side
NEXT.JS together with package NextAuth JS that provide us a better solution for handling logon and logoff event in a seamless way. Retrieve session to identity user’s permission and role would be the common approach. The story log down how to get back session data on both server and client side.
For Server side was quite easy to get back the session by the help of NextAuth JS built-in function getServerSession. Sinppet code as below:
// app/xxxx.tsx (server component)
import { authOptions } from 'pages/api/auth/[...nextauth]'
import { getServerSession } from "next-auth/next"
export async function handler(req, res) {
const session = await getServerSession(req, res, authOptions)
// ...
But for the client, we need do more effect to get back session. Especially the UI part on the client side like buttons need to handle submit action but interactive with session data as well. Below was snippets code:
// app/.../AuthProvider.tsx
'use client'
import { Session } from "next-auth"
import { SessionProvider } from "next-auth/react"
interface AuthProviderProps {
children: React.ReactNode
session: Session
}
export const AuthProvider = ({ children }: AuthProviderProps) => {
return (<SessionProvider>{children}</SessionProvider>)
}
SessionProvider should be on the client side.
// app/loyout.tsx
import { AuthProvider } from './context/AuthProvider'
import { Session} from 'next-auth'
import { NextRequest } from 'next/server'
import { headers } from 'next/headers'
const getSession = async (cookie: string): Promise<Session> => {
const response = await fetch(`${process.env.NEXTAUTH_URL}/api/auth/session`, {
headers: {
cookie
}
});
const session = await response.json();
return Object.keys(session).length > 0 ? session : null;
}
export default async function RootLayout({
children
}: {
children: React.ReactNode
}) {
const session = await getSession(headers().get('cookie') ?? '')
// we could also used below instead
//const session = await getServerSession() as Session
return (
<html lang="en">
<body className={inter.className}>
<AuthProvider session={session}>
<main className='h-screen flex flex-col justify-center items-center'>
{children}
</main>
</AuthProvider>
</body>
</html>
)
}
Since layout.tsx was under server side, we could easily call function: getServerSession() instead.
Then from the UI component under client side:
// app/.../ui/ProfileSheet.tsx
'user client'
import { useSession } from 'next-auth/react'
import React, { useEffect, useState } from 'react'
const ProfileSheet = () => {
const [form, setForm] = useState({
id: '',
username: '',
email: ''
})
// get session data here
const { data: session } = useSession()
// onclick action for the save button
const updateUserProfile = async () => {
// ...
}
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
setForm((prev) => ({
...prev,
[e.target.name]: e.target.value
}))
}
useEffect(() => {
setForm((prev) => ({
...prev,
id: session?.user.id || '',
username: session?.user.username || '',
email: session?.user.email || ''
}))
}, [session])
// ...rest of UI
}