
이전에 작성한 [Next.js14] NextAuth v5로 인증 구현하기 (1) - 로그인/로그아웃에 이어서 기록을 남긴다
이번에는 현재 로그인 되어있는 유저의 세션을 가져와 유저의 정보를 조회하고 수정하는 방법에 대해 다룬다.
이번에도 폴더 구조부터 살펴보겠다

이전 코드에서
src/app/api/auth/[...nextauth]/route.ts
src/app/client/page.tsx
src/ui/update_button.tsx
src/auth_wrapper.tsx
이렇게 총 4개의 파일이 추가되었다.
우선 Next의 Server Side Rendering과 Client Side Rendering을 구분하는 방법에 대해 짚고 넘어가겠다. 둘의 차이와 장단점에 대해서는 인터넷에 자료가 많기 때문에 추가설명은 하지 않겠다.
Next14에서 코드를 작성하여 웹페이지에 컴포넌트를 띄울때 기본적으로 Server Side Rendering을 수행한다. 코드의 최상단에 "use client"를 작성하면 Client Side Rendering을 수행한다.
Server Side코드에 console.log('메세지')를 추가하면 Next 앱을 실행 중인 cmd/terminal에 메세지가 나타나고 Client Side코드에 추가하면 브라우저->개발자 도구-> Console 에도 메세지가 나타난다.
다음과 같이 src/app/page.tsx에 console.log를 추가하고 src/app/client/page.tsx 코드를 작성해보자
// src/app/page.tsx
...
export default async function Home() {
console.log('서버 렌더링') // console.log 추가
return (
...
// src/app/client/page.tsx
"use client"
export default function Page() {
console.log('클라이언트 렌더링')
return (
<div className="flex flex-col">
<h1>클라이언트 렌더링 페이지</h1>
<h2>인증 없이 못보는 화면</h2>
</div>
)
}
이제 http://localhost:3000/ 에 접속해보면
터미널에 '서버 렌더링' 메세지가 찍혀있는 것을 확인할 수 있고
http://localhost:3000/client 에 접속해보면
터미널과 브라우저 콘솔에 '클라이언트 렌더링' 메세지가 찍혀있는 것을 확인할 수 있다!
(브라우저에 메세지가 여러번 찍히는 이유)
앞서 SSR과 CSR을 짚고 넘어간 이유는 Server side와 Client side 코드에서 세션을 호출하는 방법이 다르기 때문이다
먼저 Server side에서 호출하는 방법은 src/auth.ts파일과 src/app/page.tsx파일을 수정 후 확인할 수 있다.
// src/auth.ts
...
// handlers: { GET, POST }, auth, update 가 추가되었다
export const { handlers: { GET, POST }, auth, signIn, signOut, update } = NextAuth({
...authConfig,
...
// src/app/page.tsx
import { auth, signOut } from "@/auth" // auth 추가
export default async function Home() { // async function으로 수정
console.log('서버 렌더링')
const session = await auth() // session 호출 추가
console.log(session); // console log 추가
return (
...
이제 http://localhost:3000/ 에 접속하면 터미널에 다음과 같이 세션에 담긴 유저 정보를 읽을 수 있다

Client side에서 session을 호출하는 방법은 useSession() hook을 사용하는 것이다. useSession()을 사용하기 위해서는 사전 준비가 필요하다. 내부 api를 설정하고 useSession()이 호출 되는 곳보다 상단에 SessionProvider가 감싸져 있어야 한다.
// src/app/api/auth/[...nextauth]/route.ts
export { GET, POST } from "@/auth"
export const runtime = "edge"
// src/app/auth_wrapper.tsx
"use client";
// SessionProvider를 사용하기 위해 CSR이 필요하기 때문에
// 따로 파일을 만들어 AuthWrapper를 정의한다
import { SessionProvider } from "next-auth/react";
type Props = {
children:React.ReactNode;
}
export default function AuthWrapper({ children }: Props) {
return <SessionProvider>{children}</SessionProvider>;
}
// src/app/layout.tsx
import type { Metadata } from 'next'
import { Inter } from 'next/font/google'
import './globals.css'
import AuthWrapper from './auth_wrapper'
const inter = Inter({ subsets: ['latin'] })
export const metadata: Metadata = {
title: 'Create Next App',
description: 'Generated by create next app',
}
export default function RootLayout({
children,
}: {
children: React.ReactNode
}) {
return (
<html lang="en">
<body className={inter.className}>
<AuthWrapper> // AuthWrapper로 전체 어플을 감싸준다.
{children}
</AuthWrapper>
</body>
</html>
)
}
여기서 layout.tsx는 Next에서 특별한 기능을 하는 파일이며 page.tsx의 부모가 되는 컴포넌트다. Nextjs 공식문서
Client 페이지를 다음과 같이 수정해보자
// src/app/client/page.tsx
"use client"
import { useSession } from "next-auth/react" // import 추가
export default function Page() {
console.log('클라이언트 렌더링')
const { data: session, update } = useSession() // useSession()추가
console.log(session); // console.log 추가
return (
<div className="flex flex-col">
<h1>클라이언트 렌더링 페이지</h1>
<h2>인증 없이 못보는 화면</h2>
</div>
)
}
이제 http://localhost:3000/client 에 접속하여 브라우저 콘솔을 열어보면 다음과 같이 세션에 담긴 유저 정보를 읽을 수 있다

NextAuth V5 전에는 session update는 클라이언트 측에서만 허용됐다. v5가 출시 되면서 서버 측에서도 session update 함수가 생겼다.
우선 src/auth.ts파일 부터 수정하겠다. callbacks 내의 jwt에 trigger 관련 함수가 추가 되었다
// src.auth.ts
import NextAuth from 'next-auth';
import { authConfig } from './auth.config';
import Credentials from 'next-auth/providers/credentials';
import { User } from '@/lib/definitions';
export const { handlers: { GET, POST }, auth, signIn, signOut, update } = NextAuth({
...authConfig,
providers: [
Credentials({
async authorize(credentials) {
if (credentials.id && credentials.password) {
// 백엔드에서 로그인 처리
let loginRes = {
success : true,
data : {
user: {
ID: "user1",
NAME: "홍길동",
EMAIL: "email@email.email",
},
}
}
if (!loginRes.success) return null;
const user = {
id: loginRes.data.user.ID ?? '',
name: loginRes.data.user.NAME ?? '',
email: loginRes.data.user.EMAIL ?? '',
} as User;
return user;
}
return null;
},
})
],
callbacks: {
async session({ session, token }) {
session.user = token.user as User
return session;
},
async jwt({ token, user, trigger, session }) {
if (user) {
token.user = user;
}
// ***************************************************************
// 추가 된 코드
if (trigger === "update" && session) {
token = {...token, user : session}
return token;
};
// **************************************************************
return token;
},
},
});
이번엔 클라이언트 측 코드부터 살펴보겠다
"use client"
import { User } from "@/lib/definitions"
import { useSession } from "next-auth/react"
import { useEffect, useState } from "react"
export default function Page() {
const { data: session, update } = useSession()
// Session이 완전히 불러와진 후에 UI가 렌더링 될 수 있도록 useState와 useEffect를 사용했다
const [user, setUser] = useState<User>({} as User)
useEffect(() => {
if(session && session.user)
{
setUser(session.user as User)
console.log(session.user)
}
}, [session])
return (
session && // 세션이 완전히 불러와진 후 UI 렌더링
<div className="flex flex-col">
<h1>클라이언트 렌더링 페이지</h1>
<h2>인증 없이 못보는 화면</h2>
<br />
<button onClick={ () => {
// useSession()을 호출하며 받아온 update 함수를 사용한다.
update({...user, name: '클라이언트맨'});
}}>
Client Side Update
</button>
</div>
)
}
http://localhost:3000/client 에 접속하여 브라운저 콘솔을 킨 후 'Client Side Update' 버튼을 클릭해보면 다음과 같이 업데이트된 세션 정보를 출력할 것이다.

서버측에서는 두가지 방법으로 session update를 할 수 있다. 하나는 서버 컴포넌트 내에 클라이언트 컴포넌트를 불러와 Client Side Session Update를 하는 기존의 방법, 다른 하나는 NextAuth v5의 새로운 기능인 서버 내에서 @auth의 update 활용하는 방법이다

두가지 방법 모두 구현해보도록 하겠다
먼저 기존의 방식인 서버 컴포넌트 내에 클라이언트 컴포넌트를 호출하여 Session을 업데이트 하는 방법이다.
// src/ui/update_button.tsx
"use client"
import { useSession } from "next-auth/react"
export default function UpdateButton({newName} : {newName: String}) {
const { data: session, update } = useSession()
return (
<button onClick={() => {
update({...session!.user, name: newName});
}}>
Client Side Update
</button>
)
}
src/app/page.tsx를 다음과 같이 수정해준다
import { auth, signOut } from "@/auth"
import UpdateButton from "../ui/update_button";
export default async function Home() {
const session = await auth()
const user = session!.user;
console.log(user)
return (
<div>
<h1>홈 페이지</h1>
<h2>인증 없이 못보는 화면</h2>
<form
action={async () => {
'use server';
await signOut();
}}
>
<button>
로그아웃
</button>
</form>
<br />
<UpdateButton newName={'서버맨'} />
</div>
)
}
이제 http://localhost:3000/ 에 접속하여 'Client Side Update' 버튼을 누른 후 페이지를 새로고침 하여 terminal을 보거나 http://localhost:3000/client 에 접속하여 브라우저 콘솔을 봐보자. Session내의 user.name이 '서버맨'으로 업데이트 된 것을 확인할 수 있다!

src/app/page.tsx를 다음과 같이 수정해준다
import { auth, signOut, update } from "@/auth"
import UpdateButton from "../ui/update_button";
export default async function Home() {
const session = await auth()
const user = session!.user;
console.log(user)
return (
<div>
<h1>홈 페이지</h1>
<h2>인증 없이 못보는 화면</h2>
<form
action={async () => {
'use server';
await signOut();
}}
>
<button>
로그아웃
</button>
</form>
<br />
<form
action={async () => {
'use server';
await update({...user, name: '서버서버맨'});
}}
>
<button>
Server Side Update
</button>
</form>
{/* <UpdateButton newName={'서버맨'} /> */}
</div>
)
}
이제 http://localhost:3000/ 에 접속하여 'Server Side Update' 버튼을 누른 후 페이지를 새로고침 하여 terminal을 보거나 http://localhost:3000/client 에 접속하여 브라우저 콘솔을 봐보자. Session내의 user.name이 '서버서버맨'으로 업데이트 된 것을 확인할 수 있다!
글을 쓰다보니 최대한 자세하게 쓰게되어 길어진 것 같다... 자세히 쓴 만큼 이해가 잘 됐기를 바란다.
다음으로는 NextAuthV5를 이용한 구글 로그인에 대해 다뤄보고 Nextjs14 - NextAuthV5 시리즈를 마칠 것이다!
next 첨인데 이거 보고 드디어 성공했어요! 감사합니다.