지난 번에는 Next-auth를 이용해서 간단하게 카카오 로그인을 구현해 봤다.
React를 사용 했을 때와 비교해 봤을때, 초기에 세팅하는 구조가 달라서 조금 헷갈릴 수 있겠지만
사용하는 방법은 (개인적으로) 월등하게 편하게 사용할 수 있지 않나 하는 생각이 든다.
거기다가 useSession을 사용하면 어떤 페이지에서도 가져와서 사용할 수 있다는 점도 좋은 점 중 하나인 것 같다.
그렇게 카카오 로그인을 해결한 개발자는 오래오래 행복하게 살ㅇ...
뭐가 문젠데?
현재까지 적용한 것만 보면 카카오에서 전달해준 유저의 기본적인 정보와
카카오에서 제공하는 토큰을 사용할 수 있게 됐다.
그러나 서버의 API는 카카오의 토큰을 사용할 수 없고, 서버에서 제공해 주는 토큰을 사용해야만 통신을 할 수 있다.
그래서 이번에는 next-auth에 있는 callback을 활용해 보고자 한다.
Callbacks
...
callbacks: {
async signIn({ user, account, profile, email, credentials }) {
return true
},
async redirect({ url, baseUrl }) {
return baseUrl
},
async session({ session, user, token }) {
return session
},
async jwt({ token, user, account, profile, isNewUser }) {
return token
}
...
next-auth에서 제공하는 callback의 종류는 다음과 같다.
내가 이번 프로젝트에 사용했던 callback은 signIn / jwt / session 이 3가지를 사용했다.
// app/api/auth/[...nextauth]/route.ts
import { NextAuthOptions } from "next-auth";
import kakaoProvider from "next-auth/providers/kakao";
export const authOptions: NextAuthOptions = {
providers: [
kakaoProvider({
clientId: process.env.KAKAO_CLIENT_ID as string,
clientSecret: process.env.KAKAO_CLIENT_SECRET as string,
}),
],
callbacks: {
...
};
callback의 사용 위치는 다음과 같은데, 공식문서는 page router 기준으로 작성이 되어있어서
아 app router는 뭔가 또 다르겠구나..! 했는데, 몇 시간의 삽질 후 적용된 것을 보니 그냥 똑같다..ㅎ
Signin
// data의 타입
export interface DefaultSession {
user?: {
name?: string | null
email?: string | null
image?: string | null
}
expires: ISODateString
}
저번 글의 끝 부분을 생각해 보면 next-auth에서 useSession을 사용해서 data라는 값을 가져와서 사용할 수 있었는데,
data를 들여다보면 위와 같은 구조를 가지고 있는 것을 볼 수 있다.
여기서 user라는 키에 name, email, image 값을 지닌 객체가 들어가 있는 것을 볼 수 있는데,
이 값은 기본적으로 카카오에서 보내주는 값이지만, 서비스에 맞게 세팅을 해 줄 수도 있다.
...
async signIn({ user, account }) {
const data = await postLogin(account?.access_token || ""); // 서버와의 통신
if (account?.provider) {
user.name = data.user.name;
user.id = data.user.userSeq;
account.access_token = data.token.accessToken;
account.issuedAt = data.token.issuedAt;
}
return true;
},
...
나는 그 세팅을 우선 signIn callback에서 진행해 줬는데,
해당 callback에서 서버에 카카오에서 제공해 준 토큰을 담아 전달하면
유저의 이름, 번호, 서버 토큰을 받아오게 되고 해당 값을 각각 user 와 account의 데이터에 맞게
값을 다시 할당해 주었다.
여기서 하나 참고할만한 점은, Signin callback은 다른 callback과는 다르게 유일하게 boolean 값을 반환한다.
이게 만약 false라면 로그인이 거부되는 형태가 될 것이다.
그래서 그런 것도 생각해서 만약 카카오에서 토큰은 받았는데 어떠한 분기처리가 필요하다면
여기서 진행해 줘도 될 것 같다.
jwt
...
async jwt({ token, account, user }) {
if (account) {
token.accessToken = account.access_token;
token.issuedAt = account.issuedAt;
}
return token;
},
...
jwt callback은 토큰과 관련된 데이터를 다룰때 사용한다.
공식 문서에서는 로그인 혹은 클라이언트에서 세션에 접근 할 때 마다 호출이 되는 callback이라고 설명한다.
이 callback에서 나는 signin callback에서 세팅했던 토큰을 재할당 해 주었다.
이렇게 재할당 해준 이유는 결국 여기에서 세팅한 값들을 클라이언트 사이드에서 사용해야 하는데
이 callback은 서버 사이드에서 이뤄지는 형태라서 내가 필요한 데이터를 바로 클라이언트에 저장할 수 없기 때문이다.
그래서 세팅한 token이라는 데이터를 다시 반환해준다.
session
...
async session({ session, token }) {
if (token.accessToken) {
session.user.id = token.sub || "";
session.user.accessToken = token.accessToken as string;
session.user.issuedAt = token.issuedAt;
}
return session;
},
...
공식 문서에서 session callback에 대한 내용을 들여다 보면
jwt callback을 통해 토큰에 추가한 항목을 사용할 수 있게 하려면
여기에 명시적으로 전달하여 클라이언트가 사용할 수 있게 해야 합니다.
라고 적혀있다.
즉, 결과적으로 위의 여러 callback에서 세팅했던 내용들을 session이라는 callback에서 처리해줘야
실제적으로 클라이언트에서 사용할 수 있는 데이터가 만들어진다는 얘기가 되겠다.
그래서 필요한 값들을 session.user에 넣어줬는데, 여기서 약간의 오류가 생길 수 있다.
// data의 타입
export interface DefaultSession {
user?: {
name?: string | null
email?: string | null
image?: string | null
}
expires: ISODateString
}
다시 data의 타입을 살펴보면 user 객체 안에 name, email, image 만 데이터가 있는데
위의 session callback을 보면 여기에 없는 id, accessToken, issuedAt 이라는 키에 데이터를 할당하고 있다.
// types/next-auth.d.ts
import "next-auth";
declare module "next-auth" {
interface User {
id: string;
name: string;
email: string;
image: string;
accessToken: string;
issuedAt: string;
}
interface Session extends DefaultSession {
user: User;
expires: string;
error: string;
}
}
이럴 때는 위와 같이 next-auth.d.ts 파일을 만들어서 사용해 주면 된다.
next-auth에서 사용하는 Session의 타입을 재정의 하는 과정이라고 생각하면 될 것 같다.
이렇게 파일을 만들어주면 원하는 값을 callback 과정에서 세팅해서 useSession을 통해
클라이언트에서 사용할 수 있게 된다.
참고 자료
- next-auth.d.ts 관련 에러 해결할 때 참고한 글
'Stack > Next.js' 카테고리의 다른 글
[Saida Lab] Next-auth 적용하기 (3)_build error (1) | 2024.03.17 |
---|---|
[Saida Lab] Next-auth 적용하기 (1)_app router + kakao Login (0) | 2024.03.15 |