[NextAuth] NextAuth에서 credentials 에러 핸들링하기

임홍원·2024년 1월 24일
post-thumbnail

NextAuth에서 에러 핸들링을 한 경험을 공유하기 위해 이 글을 작성한다.

개요

NextAuth를 보통 소셜로그인 용도와 이메일 비밀번호 로그인만 진행하고, 에러핸들링을 하는 포스트를 생각보다 찾기 힘들었어서 나의 에러핸들링 경험을 공유 할 것이다.

우선 Next.js Route handlers에서 유저의 정보를 제대로 받아오지 못했었다.

원인파악

  • NextAuth Credentials에서의 문제점인가?
    • NextAuth에서 Credentials에서 로직을 잘못 작성한것이 문제점
  • onSubmit 함수에서 문제점인가?
    • onSubmit 함수에서 NextAuth의 Signin 결과를 받아오지 못하고 있었음
  • Route Handlers가 제대로 동작하는가?
    • Route Handlers의 로직을 잘못 작성하였음
// api/auth/[...nextauth]/route.ts
async authorize(credentials) {
        if (!credentials) {
          throw new Error('입력 값이 잘못되었습니다.');
        }
        // supabase에서 데이터 가져와서 객체를 만든 후 return
        const { password } = credentials;
        const companyUser = await supabase
          .from('company_user')
          .select('id, email, name, password, role')
          .eq('email', `${credentials?.email}`)
          .single();

        const userData = companyUser.data;

        if (userData) {
          const result = await bcrypt.compareSync(
            password,
            userData?.password as string,
          );
          if (!result) {
            return null;
          }
        }
        return userData;
      },

authorize 안에서 userData값을 return 해주었다.

// api/auth/signup/route.ts
import { CompanyUserSignUpType } from '@/types/auth';
import bcrypt from 'bcrypt';
import { NextRequest, NextResponse } from 'next/server';
import { supabase } from '../../db';

export const POST = async (req: NextRequest) => {
  const userData = await req.json();
  const { data } = await supabase
    .from('company_user')
    .select('email')
    .eq('email', userData.email)
    .single();

  if (data) {
    return NextResponse.json({
      status: 409,
      message: '이미 가입되어있는 이메일 입니다!',
    });
  }

  const hashedPassword = await bcrypt.hashSync(userData.password, 5);

  const { error: saveError } = await supabase
    .from('company_user')
    .insert<Omit<CompanyUserSignUpType, 'confirmPassword'>>({
      ...userData,
      password: hashedPassword,
    });

  if (saveError) {
    return NextResponse.json({
      status: saveError.code,
      message: '회원가입에 실패하였습니다!',
    });
  }

  return NextResponse.json({ status: 200, message: '회원가입 완료!' });
};

Request가 클라이언트로부터 들어오면 해당되는 status, message로 구성된 객체를 Response로 반환하였다.

  const onSubmit = async (data: CompanyUserSignUpType) => {
    const userData = {
      email: data.email,
      name: data.name,
      password: data.password,
    };

    const res = await fetch('/api/auth/signup', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
      },
      body: JSON.stringify(userData),
    });
    const message = await res.json();
    if (message.status === 409) {
      toast.error(message.message);
    }

    if (message.status === 200) {
      toast.success(message.message);
      router.push('/auth/signin');
    }
  };

onSubmit 함수를 통해 Route handlers의 주소로 요청을 보내고 이 요청을 받아 toast로 출력해주었다.

profile
Frontend Developer

0개의 댓글