auth.ts는 서버에서 처리가 이루어지고 있으니, 여기서는 next/headers에서 제공하는 cookies를 사용해야 오류가 안난다
- document.cookie
- import { Cookies } from 'react-cookie'
이런거는 사용안됨
반대로 클라이언트 컴포넌트에서는
- import { cookies } from 'next/headers'
넥스트@14 공식 cookies 쓰면 에러
이 때는 위의 react-cookie나 document 에서 쿠키를 설정해줘야 에러가 안난다
즉 쿠키 사용 시 서버 컴포넌트와 클라이언트 컴포넌트 각각 다른 것을 사용해야 하고 전역으로 상태 재사용할 때도 서버 컴포넌트와 클라이언트 컴포넌트를 분리해서 셋팅을 해줘야 한다
일단 로그인 성공 시 서버 측에서 전달한 token 값을 쿠키에 저장하고(서버)
import NextAuth from 'next-auth'
import CredentialsProvider from 'next-auth/providers/credentials'
import KakaoProvider from 'next-auth/providers/kakao'
import axios from 'axios'
import { cookies } from 'next/headers'
import cookie from 'cookie'
export const {
handlers: { GET, POST },
auth,
signIn,
} = NextAuth({
pages: {
signIn: '/login',
newUser: '/createAccount',
},
secret: process.env.NEXTAUTH_SECRET,
providers: [
CredentialsProvider({
async authorize(credentials, req) {
console.log(credentials)
const authResponse = await axios.post(
`${process.env.NEXT_PUBLIC_BASE_URL}/member/login`,
{
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
email: credentials.email,
password: credentials?.password,
}),
},
)
if (authResponse.headers['set-cookie']) {
let setCookie = authResponse.headers['set-cookie'][0] // token값을 받아와
if (setCookie) {
const parsed = cookie.parse(setCookie)
cookies().set('connect.sid', parsed['connect.sid'], parsed) //브라우저 쿠키에 저장
}
}
if (authResponse.status === 401) {
throw new Error('로그인 실패')
} else {
const { user } = await authResponse.data
return {
id: user.id, // 임시
email: user.email,
name: user.name,
image: user.image,
...user,
}
}
},
}),
// 중략
로그인 성공 시 바로 보여지는 레이아웃 내 컴포넌트에서
클라이언트 측에서 사용할 유저 데이터 저장 로직 구현
'use client'
// 중략
const { data, status } = useSession() // 유저 세션 정보(name, email, image)
const accessToken = getCookie('connect.sid')
// token 값은 별도로 로그인 과정에서 브라우저에 저장한 쿠키에서 가져온다
useEffect(() => {
LocalStorage.setAccessToken(accessToken)
axiosInstance.defaults.headers.common.Authorization = `Bearer ${accessToken}`
// axiosInterceptor header에 토큰 값 포함
}, [])
useEffect(() => {
setUser({
id: '0',
name: data?.user?.name!,
email: data?.user?.email!,
profileImage: data?.user?.image!,
accessToken: accessToken,
})
}, [data])
며칠동안 next-auth 를 아예 제외하고 처음부터 다시 로직을 짜야할까 정말 많이 고민했었는데,
next-auth에서 자체적으로 제공하는 세션 토큰은 오로지 프론트 서버(로그인) 전용,
백엔드에서 전달하는 토큰은 백엔드 서버 전용으로 아예 분리해서 생각하니까 한결 로직이 간단해졌다
물론 처음에는 받아들이기 힘들었지만 (내 머리로는 동시에 두 인증토큰을 관리한다는 게 굉장히 잘못되가는 느낌이었다) (그래서 계속 초반에 auth session에 백엔드 쪽 토큰값을 넣어서 같이 관리하려고 함)