저번 회고에서 얘기했듯이 로그인 부분 로직이 아쉽다. 왜냐하면 로그인했을때 유저 토큰을 로컬 스토리지에 저장하기 때문에 직접 지우지 않으면 계속해서 남아있다. 그리고 브라우저에서 직접 로컬스토리지의 값을 변경할 수 있기 때문에 위험하다. 그래서 NextAuth라는 next.js에서 유용하게 사용할수 있는 인증 기능을 사용해보려고 한다.
우선 해당 기능의 동작 방식을 간단하게 설명해보겠다. 로그인을 브라우저에서 관리하는 것이 아니라 NextAuth서버에서 관리하는 것이다. 그래서 로그인했을때 access여부를 서버 세션에 저장하고 세션에 저장한 값을 리스폰스로 보내주어 로그인 여부를 유지해주는 역할을 한다.
로그인 -> nextAuth서버 세션에 저장 -> 세션 저장 값 반환 -> 브라우저 저장 -> 브라우저에 저장된 세션 값 확인 -> 로그인 여부 확인
간단하게 이런 방식으로 운영된다고 생각하면 된다. 나도 완벽하게 어떤 방식으로 이뤄지는지 제대로 알지 못하기 때문에 아쉽지만 일단 지금은 이렇게 이해했다.
전에 우리가 만든 서비스에서는 로그인하면 유저 정보와 accessToken을 리스폰스로 받을 수 있었다. 그러면 브라우저 api 리스폰스 내역에서 해당 내용을 모두 확인할 수 있다. 하지만 NextAuth를 사용하면 이 부분을 보완할 수 있다.

지금 위의 이미지는 nextAuth를 통해 받은 response이다. 전에는 api결과로 모든 유저 정보가 노출됬지만 지금은 내가 원하는 값만 노출시켜놓은 상태이다.

그리고 이건 쿠키에 저장된 로그인 세션값이다. 내용을 확인해보면 개인 정보가 전혀 담기지 않았다. 내가 느낀 NextAuth를 사용하는 이유이다.
가장먼저 설치를 해준다.
npm install next-auth
이제 nextauth를 사용할 준비가 된것이다. 그리고 지금까지 사용한적 없었던 api폴더에 auth폴더를 생성해주고 auth폴더에 [...nextauth].ts라는 파일을 만들어준다.

지금 나는 pageRouter를 사용하고 있다. AppRouter는 어떻게 되는지 아직 정확하게 모르겠다.
이제 인증 코드를 작성해보자.
export const authOption = {
providers: [
...
authOption을 먼저 설정해 주어야 한다. 이제 이 옵션안에 있는 내용으로 인증을 하는 것이다.
export default NextAuth(authOption)
그리고 이 옵션을 가지고 NextAuth를 실행한다고 생각하면 된다.
NextAuth의 가장 큰 장점중에 하나가 OAuth를 지원하는 플랫폼이 많다는 것이다. OAuth는 나도 아직 실제 구현해보지 못했지만 다양한 플랫폼을 이용해 로그인을 도와주는 역할이다. 플랫폼 로그인을 했을때 로그인 세션을 설정해주고 해당 세션으로 인증을 대신해주는 것이다. 그래서 다양한 provider가 존재한다. 심지어 네이버, 카카오도 있다.
하지만 우리는 그런 플랫폼 로그인이 아니라 커스텀한 로그인을 할 것이기 때문에 CredentialsProvider를 사용할 것이다. Credentials는 신임장이라는 뜻인데 직접 신임장을 만드는 provider라고 생각하면 된다.
providers: [
CredentialsProvider({
name: 'Credentials',
credentials: {
id: { label: 'id', type: 'text' },
password: { label: 'password', type: 'password' },
},
provider설정은 간단하다. 우선 첫번째 인자로 어떤 값들로 인증을 할것인지 지정해주면 된다. 우리는 id와 password 두가지로 인증할 것이기 때문에 두가지를 지정해줬다.
그리고 provider 두번째 인자로 인증 절차를 넣어주면 된다.
async authorize(credentials) {
if (!credentials) return
const { id, password } = credentials
const response = await LoginAccess(id, password)
const { data } = response
if (data) {
return data
} else {
return null
}
위에서 provider에서 받은 id와 password값을 받아서 사용하는 것이다. 이제 여기에서 원래 사용하던 로그인 api를 넣어주는 것이다. 이 api는 브라우저에서 실행하는 것이 아니라 nextAuth 서버에서 실행하는 것이다. 그리고 해당 데이터가 유효하면 data를 리턴하고 없다면 null을 반환한다. 로그인에 성공하면 세션에 인증 정보를 저장하고 인증 세션을 보내주게 되는 것이다.
인증에는 여러 옵션이 존재한다. 이 옵션으로 인증한 내용을 어떻게 활용할지 정해주겠다.
해당 옵션은 인증한 값을 어떤 값을 기준으로 암호화할지 정해주는 것이다.
secret: process.env.NEXTAUTH_SECRET,
그래서 암호화 코드는 환경변수에 넣어서 사용해준다. nextAuth 공식 문서에서는 암호화키를 발급하는 방법도 있으니 참고해보면 좋을 것 같다. 나는 아무 문자를 집어넣었다.
nextAuth에서 /api/auth/signin이라는 주소로 접근하면 nextauth에서 지원하는 로그인 페이지로 이동시켜준다.

하지만 우리는 직접 만든 로그인 페이지가 있기에 page옵션을 추가해준다.
pages: {
signIn: '/login',
},
이렇게 옵션을 추가해주면 위의 이미지에 있는 페이지가 아니라 직접 만든 로그인 페이지로 이동시켜준다.
세션을 직접 설정하는 옵션이다. 내가 커스텀할 옵션은 세션 유지 시간이다. 지금 기본값으로는 하루가 지정되어 있다. 하루는 너무 길다고 생각해서 시간을 1시간으로 줄여보겠다.
session: {
maxAge: 60 * 60,
},
이제 세션 유지 시간은 1시간이다. 이후에 세션은 자동으로 만료되서 다시 인증을 해야하는 것이다.
중요한 옵션이다. 인증했을때 실행시킬 함수를 등록하는 것이다.
async jwt({ token, user }: { token: JWT; user: User }) {
const copyToken = { ...token }
if (user) {
copyToken.accessToken = user?.accessToken
copyToken.id = user?.user?.id
}
return copyToken
},
우선 jwt함수이다. 세션은 jwt방식으로 토큰화되서 전달되게 된다. 그래서 이 함수는 인증된 세션값을 어떻게 우리가 처리할지 지정해주는 것이다. 일단 위에서 인증에 성공한 값을 user객체로 받는다. 그리고 토큰을 리턴한다. 그래서 user에 토큰을 리턴할 토큰으로 지정해주고 id값도 지정해준다.
이 콜백은 인증한 값을 클라이언트에서 사용하도록 해주는 콜백이다.
async session({ session, token }: { session: Session; token: JWT }) {
const copySession = { ...session }
copySession.user.id = token.id
copySession.accessToken = token.accessToken
return copySession
},
jwt에서 리턴한 토큰을 받아서 사용한다. 그리고 세션에 id와 토큰으로 넣어주면 된다. 그러면 클라이언트에서 사용이 가능하다.

전에는 아무 값도 없었지만 session 콜백으로 토큰과 userid를 확인할 수 있다. 전에 사용하던 api와 다르게 모든 정보가 노출되어 있지 않고 약간만 노출되어 있다.
참고로 expires는 유효 시간이다. 지금은 1일로 설정되어 있는 것이다.
우선 기본 세팅이 됬다. 시간이 늦은 관계로 여기에서 마무리하고 직접 로그인하는 것과 로그아웃, 리펙토링까지 한번에 정리해보겠다.