이제 로그인 기능을 붙여보겠다. NextAuth.js
는 구현하기 귀찮은 인증 기능을 아주 쉽고 간단하게 만들 수 있게 해준다. 이전에도 이 블로그에, oauth 관련 포스팅을 한 적이 있다.
프론트엔드/리액트 카카오 로그인
백엔드/node.js/express 카카오 로그인
트위터 oauth1.0 인증
직접 구현하는 것은 하려고 하면 할 수는 있지만 생각할 것도 많고 번거롭고 이게 맞나..? 하는 생각이 든다. (그래도 직접 한 번은 구현 해 보면 도움이 된다.)
이제 이 과정을 간단하게 넘겨버리자.
...그러려고 했는데 신기술은 언제나 학습의 귀찮음이 따른다.
$yarn add next-auth
이걸 설치한 다음에
https://next-auth.js.org/getting-started/example
그냥 공식 문서 그대로 따라하면 되고 굳이 다시 쓰지는 않겠다. (귀찮다.)
...
const getEnv = (key: string) => {
const value = process.env[key];
if (!value) {
throw new Error(`${key}: 존재하지 않는 환경 변수`);
}
return value;
};
export default getEnv;
난 utils/getEnv.ts
파일을 만들었다. 이것으로 환경 변수를 불러오면, 오류를 던져주기 때문에 삽질을 줄일 수 있다.
그 다음엔 난 orm 으로 prisma, db는... 그냥 쓰던 게 편해서 mysql로 하겠다.
암튼 공식 문서를 보다보면 밑에 이런 게 있음.
(코드를 이미지로 올려놓은 것은 여러분을 열받게 하려고 그런 게 아니고 공식문서에 있기 때문입니다.)
이게 뭔 내용인지 이해도 안 되었는데, 일단 jwt는 oauth 에서 토큰 받을 때마다 실행이 되고 session은 session 데이터 가져올 때 실행이 된다고 함. 세션에는 기본적으로 설정되어 있는 것만 가져올 수 있고 이외의 것(예를 들어, 이메일이라든가...)가져오려면 명시적으로 추가해줘야 한다.
근데 저 코드를 무지성으로 타입스크립트에서 복붙하면 에러를 뱉음 (아놔..)
해결법은 AuthOptions 를 Import해서 타입을 붙여주는 것이다.
import NextAuth, { AuthOptions } from 'next-auth';
const prisma = new PrismaClient();
export const authOptions: AuthOptions = { //여기
providers: [
...
],
};
export default NextAuth(authOptions);
이렇게 하면 고쳐짐. 그리고 types/next-auth-d.ts 파일을 만든 뒤
import NextAuth, { DefaultSession } from 'next-auth';
declare module 'next-auth' {
/**
* Returned by `useSession`, `getSession` and received as a prop on the `SessionProvider` React Context
*/
interface Session {
accessToken: string;
user: {
accessToken: string;
} & DefaultSession['user'];
}
}
declare module 'next-auth/jwt' {
interface JWT {
accessToken: string;
}
}
이런식으로 커스텀 프로퍼티를 추가해주면 된다.
...되긴 되는데
그런데 나는 프리즈마 어댑터를 쓸 거라 그냥 안 하기로 함.
https://authjs.dev/reference/adapter/prisma
이것도 그냥 공식문서를 보자.
복붙을 하고 만들라는 파일을 만들고 db 서버가 로컬이면 실행도 해주고 올바른 db url을 만들고 이것저것 하고 마이그레이션도 하면 알아서 다 해준다.
import { useSession, signIn, signOut } from 'next-auth/react';
export default function Component() {
const { data: session } = useSession();
if (session) {
console.log(session)
return (
<>
Signed in as {session.user?.email} <br />
<button onClick={() => signOut()}>Sign out</button>
</>
);
}
return (
<>
Not signed in <br />
<button onClick={() => signIn('discord')}>Sign in</button>
</>
);
}
하지만 기본 제공하는 인증 창 보다는 커스텀한 디자인을 쓰고 싶으니 이런식으로 signIn, signOut 함수를 버튼에 붙일 수 있다.
하지만 디자인은 아직 없다.😃
누르면 나의 경우 디스코드 인증창이 뜨고, 승인을 하고 돌아오면 이메일이 표시되며 사인 아웃 버튼으로 바뀐다.
db에도 잘 저장이 된다.
정말 쉽게 로그인을 만들었다.
아직 모든 게 다 익숙하지 않고 프리즈마는 또 어떻게 다루는 건지 하나도 모르지만 로그인만은 구현완료했다!
다음에는 뭘 할지 그건 다음에 생각해보겠다. 그리고 프리즈마에 대해서도 좀 더 알아보아야 한다. (뭐가 어쨌든 sequelize 문서를 보는 것보단 낫지 않을까 싶다)