혹시나 예제 코드가 필요하신 분들은 해당 링크에서 받아가세요!
오늘은 저번시간에 이어서 NextAuth.js 사용법에 대해서 알아볼 예정이다.
저번 포스팅이 너무 길어지는 탓에 간략하게 맛보기만 다뤘었는데 이번에는 조금 더 NextAuth에 대해서 살펴보고 커스텀해서 사용 할 수 있는 방법에 대해서 다뤄보도록 하겠습니다.
npm install --save next-auth 와 npm install -D @types/next-auth 설치pages > api > auth > [...nextauth].ts 파일 생성[...nextauth].ts 파일에 다음 내용을 작성import NextAuth from "next-auth"
import Providers from "next-auth/providers"
import {NextApiRequest} from "next";
export default NextAuth({
providers: [
Providers.Credentials({
name: "email-password-credential",
credentials: {
email: { label: "Email", type: "email", placeholder: "test@test.com" },
password: { label: "Password", type: "password" }
},
async authorize(credentials: Record<any, any>, req: NextApiRequest){
return credentials;
}
})
]
})
pages > index.tsx 화면을 다음과 같이 수정import { useSession, signIn, signOut } from "next-auth/client"
const Login = () => {
const [session, loading] = useSession();
if (session) {
return (
<>
Signed in as {session.user.email} <br />
<button onClick={() => signOut()}>Sign out</button>
</>
)
}
return (
<>
Not signed in <br />
<button onClick={() => signIn()}>Sign in</button>
</>
)
}
export default Login;
npm run dev로 실행시키고 http://localhost:3000 으로 접속해서 로그인 테스트물론 NextAuth 에서 생성해주는 로그인 뷰를 그대로 사용하고 싶은 사람들은 필요 없는 내용일지 모르지만 아마도 직접 만든 로그인 화면에 NextAuth를 붙이고 싶은 사람들이 더 많을 것 같다.
따라서 자신이 만든 로그인 화면에서 로그인 버튼을 클릭하면 NextAuth 인증이 이루어질 수 있는 방법을 소개하도록 하겠다.
먼저 [...nextauth].ts 파일을 열 수 있도록 한다. 그 다음 설정을 하나 추가해주도록 하자.
export default NextAuth({
providers: [
Providers.Credentials({
name: "email-password-credential",
credentials: {
email: { label: "Email", type: "email", placeholder: "test@test.com" },
password: { label: "Password", type: "password" }
},
async authorize(credentials: Record<any, any>, req: NextApiRequest){
return credentials;
}
})
],
// 추가
pages: {
signIn: '/login',
}
})
여기서 추가되는 pages 라는 설정은 기존에 NextAuth 가 설정해둔 여러가지 화면들을 자기가 원하는 화면으로 매핑시켜주는 설정이라고 생각하면 쉬울 것 같다. 로그인 뷰 말고도 여러가지 커스텀 화면을 매핑할 수 있으므로 더 많은 정보를 원하면 링크에서 찾아보면 될 것 같다.
따라서 현재 우리는 로그인 버튼을 누르면 /login URL로 이동하도록 만들어두었다.
(http://localhost:3000/login 으로 이동하게 된다.)
그럼 한 번 살펴보도록 하자.
http://localhost:3000 으로 들어가서 Sign in 버튼을 클릭하면 다음과 같은 화면이 뜬다.

현재는 login 화면을 만들지 않았기 때문에 404 뜨는것이 당연합니다.
URL에 http://localhost:3000/login?callback=<콜백주소> 라고 뜨면 정상적으로 설정된 것 입니다.
일단 설정은 정상적으로 되었으니 로그인 화면을 만들어보도록 하자. Next.js는 pages 하위에 파일을 생성하면 라우팅이 자동으로 되므로 pages 하위에 login.tsx 파일을 하나 생성하면 http://localhost:3000/login 주소로 접속할 때 해당 화면이 실행이 될 것이다.
login.tsx 화면은 다음과 같이 작성해본다.
const Login = () => {
return (
<form>
<label>
이메일 :
<input type="email" name="email" placeholder="test@test.com" />
</label>
<label>
비밀번호 :
<input type="password" name="password" />
</label>
<button type="submit">로그인</button>
</form>
)
}
export default Login;
화면 디자인은 따로 하지 않았습니다. (제가 잘 못해서..^^;;)
작성하고 저장한다음 http://localhost:3000/login 으로 들어가면 다음과 같은 화면이 나온다.

아직까지는 로그인 버튼을 클릭하면 화면이 새로고침만 되고 아무런 반응이 일어나지 않을 것이다. 이제부터 로그인 버튼을 누르면 정상적으로 로그인 처리가 될 수 있도록 해보자
다시 login.tsx 파일을 열고 다음과 같이 코드를 추가한다.
import { signIn } from "next-auth/client";
const Login = () => {
// 추가
const login = async (e: any) => {
// 원래 실행되는 이벤트 취소
e.preventDefault();
// Form 안에서 이메일, 패스워드 가져오기
const email = e.target.email.value;
const password = e.target.password.value;
const response = await signIn("email-password-credential", {
email,
password,
redirect: false
});
console.log(response);
}
return (
// onSubmit에 login 함수 등록
// 로그인 버튼을 클릭하면 login 함수가 실행된다.
<form onSubmit={login}>
<label>
이메일 :
<input type="email" name="email" placeholder="test@test.com" />
</label>
<label>
비밀번호 :
<input type="password" name="password" />
</label>
<button type="submit">로그인</button>
</form>
)
}
export default Login;
지금 이 코드에서 봐야할 핵심 부분은 signIn 이다. 무언가 길게 string으로 적히고 옵션값이 정의되어있는데, signIn 이 바로 [...nextauth.ts] 에 정의된 Provider 를 호출하는 함수이다. 그 중에서도 따옴표 사이에 적힌 ID 값에 해당하는 Provider 를 호출한다.
하지만 우리는 Provider 에 ID를 지정해준 적이 없다. 그럼 지정해주면 된다.
[...nextauth.ts] 파일을 열고 다음과 같이 수정해준다.
providers: [
Providers.Credentials({
// 수정
id: "email-password-credential",
name: 'Credentials',
type: 'credentials',
credentials: {
email: { label: "Email", type: "email", placeholder: "test@test.com" },
password: { label: "Password", type: "password" }
},
async authorize(credentials: Record<any, any>, req: NextApiRequest){
return credentials;
}
})
],
name옵션은NextAuth에서 만들어주는Form태그의 로그인 버튼에 노출될 텍스트를 적는 부분이다.
이렇게 수정을 완료했으면 값을 입력하고 로그인 버튼을 클릭해보자.
(redirect를 false를 했기 때문에 callback URL로 이동하지 않는다.)
.gif)
다음과 같이 response 정보가 error: null 인 형태로 떴다면 아주아주 지금까지 잘 따라와준거다. 우리가 입력한 email과 password는 정보는 그럼 어디로 들어간걸까?
이전에도 말했듯이 [...nextauth].ts 파일의 authorize 부분의 credentials 파라미터에에 JSON 형태로 전달된다. 콘솔로 찍어보면 다음과 같이 나온다.
async authorize(credentials: Record<any, any>, req: NextApiRequest){
console.log(credentials);
return credentials;
}

따라서 authorize 부분에서 이제 로그인 인증 처리를 해주면 되는데 우리는 간략하게 if 문을 이용해서 해보도록 하자. authorize 코드를 다음과 같이 수정해준다.
async authorize(credentials: Record<any, any>, req: NextApiRequest){
const email = credentials.email;
const password = credentials.password;
if(email === "test@test.com" && password === "test"){
return credentials;
}
throw new Error("아이디 혹은 패스워드가 틀립니다.");
}
이메일이 test@test.com 이면서 패스워드가 test 이면 credentials 를 리턴해주면서 정상적으로 인증이 되었다고 알려줍니다. 반대로 이메일이나 패스워드중 둘 중 하나라도 틀리면 에러를 던져서 사용자에게 알려줄 수 있도록 합니다.
❗ 여기서 유저들에게 정보 전달은 명확하게 한다고 아이디가 틀리면 아이디가 틀렸다, 패스워드가 틀리면 패스워드가 틀렸다고 특정해서 전달하시는 분들이 간혹 있다. 그렇게 하게 되면 해커들이 아이디의 존재 유무를 파악하고 해킹 공격을 할 수 있기 때문에 로그인 부분에서는 불친절하게 에러 메시지를 간결하게 띄우는 것이 좋다.
그리고 코드를 저장한 후 다시 로그인을 진행해보자.
.gif)
.gif)
Response 응답이 다르게 들어온 것을 알 수 있다.
따라서 Response 의 Error 의 유무를 이용해서 인증이 되었는지, 아니면 에러 메시지를 띄워서 사용자에게 로그인을 다시 시도하게 할지를 확인하면 될 것 같다.
오늘 포스팅이면 로그인 부분에 대해서는 끝낼 수 있을 줄 알았는데 하다보니 내용이 많이 길어졌다. 다음 포스팅을 마지막으로 로그인을 마무리하고 본격적인 Next.js의 SSR 렌더링에 대해서 알아보는 시간을 가질 수 있도록 하겠다.
긴 글 읽어주셔서 감사드리고 혹시 잘못된 부분이 있어가 추가했으면 하는 내용들이 있으면 댓글로 작성해주시면 빠르게 피드백 하겠습니다.
좋은글 잘봤읍니다,,, ^^