React.js

간편 회원가입 api 없는 간편 회원가입 만들기 (feat. 카카오 간편 로그인)

2025. 10. 29. 16:46

개요

투두 리스트 기반 협업 툴을 개발 중인데, 백엔드 api에 카카오 간편 로그인 api가 있어서 당연히 간편 회원가입 api도 있을 거라고 생각했지만 없었다.

하지만 요구사항에는 간편 회원가입도 구현하라고 나와있어서 방법을 고안해야 했다.

(물론 백엔드 api 개발을 요청드리는게 가장 빠르고 확실한 방법이지만, 당시 백엔드 팀과 소통할 수 없는 제약사항이 있었다.)

 

백엔드에서 구현해놓은 카카오 간편 로그인 api는 정말 '간편한 로그인'에 초점이 맞춰져 있었다.

서버에 회원으로 등록된 카카오 계정이 아닐 경우, 자동으로 회원가입까지 진행시키고 나서 로그인을 완료시켜주기 때문에 별도의 간편 회원가입 단계가 사실상 필요하지 않은 구조였다.

 

하지만 요구사항에 의하면 회원가입 폼에서 카카오 버튼 클릭 시 간편 회원가입을 진행해야 했으며,

간편 회원가입 폼에서는 '닉네임'만 따로 입력받아 가입을 완료시켜야 했다.

 


구현: 간편 로그인 api 응용

0. OAuth 파이프라인 다이어그램 참고

기능을 구현하기 전, Kakao Developers에 나와있는 카카오 OAuth 파이프라인 다이어그램을 참고했다.

OAuth 인증 시스템 구현 방향을 잃지 않는 데에 많은 도움이 되었다. 

https://developers.kakao.com/docs/latest/ko/kakaologin/rest-api#request-code

 

 

1. 인가 코드 받기

간편 로그인/회원가입 버튼을 하나의 `KakaoOAuthButton`으로 만들고, 클릭 시 인가 코드를 요청하는 url로 이동시켰다.

이 url은 카카오 인가 코드를 요청하기 위한 공식 주소로 보면 될 것 같다.

export default function KakaoOAuthButton() {
  const handleKakaoOauth = () => {
    const url = `https://kauth.kakao.com/oauth/authorize?response_type=code&client_id=${import.meta.env.VITE_KAKAO_REST_API_KEY}&redirect_uri=${KAKAO_REDIRECT_URI}`;

    window.location.href = url;
  };
  
  return ( // ... )
}

 

 

회원가입 폼에서 해당 버튼을 누르면 아래와 같은 페이지로 이동되고, 인가 코드를 받을 수 있다.

 

여기서 '확인하고 계속하기'를 누르면 인가 코드를 받고, redirect uri로 페이지를 이동한다.

 

 

2. 리다이렉트 페이지에서 간편 로그인/회원가입 분기 처리

우선 `redirect_uri` 경로 페이지는 직접 만들어서 라우팅 경로에 추가해야 하고,

Kakao Developers에서 앱 등록 후 리다이렉트 URI에 개발 서버 주소와 배포 서버 주소의 경로를 추가해야 된다.

{
    // oauth 경로
    path: '/oauth',
    element: <Layout />,
    errorElement: <ErrorPage />,
    children: [
      {
        path: 'kakao',
        element: withAuth(<KakaoRedirectPage />),  // 간편 로그인/회원가입 분기 처리하는 리다이렉트 페이지
      },
      {
        path: 'signup/kakao',
        element: withAuth(<KakaoSignUpPage />),  // 분기 처리 시 state='signup'이면 연결되는 간편 회원가입 페이지
      },
    ],
},

 

이렇게 하면 인가 코드가 리다이렉트 페이지 주소에 쿼리 파라미터로 잘 추가된다.

주소값으로 넘어온 인가 코드는 미리 만들어둔 `KakaoRedirectPage`에서 `URLSearchParams`를 통해 가져올 수 있다. 

export default function KakaoRedirectPage() {
  const navigate = useNavigate();
  const setUser = useSetAtom(userAtom);

  useEffect(() => {
    const params = new URLSearchParams(window.location.search);
    const code = params.get('code'); // URL 파라미터에 담긴 인가 코드

    if (!code) return;

    const handleSignInKakao = async () => {
      try {
        // 1. 공통적으로 간편 로그인 진행
        const { data } = await axiosInstance.post('/auth/signIn/KAKAO', {
          redirectUri: KAKAO_REDIRECT_URI,
          token: code,
        });

        setTokens(data.accessToken, data.refreshToken);

        // 2. 이미 회원가입을 거쳤던 사용자는 간편 회원가입 생략 → 바로 로그인 처리
        // 회원가입 폼에서 닉네임 변경 시 createdAt과 updatedAt이 달라진다는 점을 이용
        if (data.user.createdAt !== data.user.updatedAt) {
          // /user 데이터 저장
          const { data: userRes } = await axiosInstance('/user');
          setUser(userRes);

          navigate('/', { replace: true });
          toast.success(`환영합니다, ${data.user.nickname}님!`);
        } else if (data.user.createdAt === data.user.updatedAt) {
          // 2-1. 신규 카카오 유저는 간편 회원가입 페이지로 이동
          navigate('/oauth/signup/kakao', { replace: true });
        }
      } catch (error) {
        if (axios.isAxiosError(error)) {
          // 로그인 요청 실패 에러 처리...
        }
      }
    };

    handleSignInKakao();
  }, [navigate, setUser]);

 

여기서 `/auth/signIn/KAKAO` 엔드포인트에 넘겨주는 인가 코드는 백엔드로 전달되고,

`redirectUri`는 현재 페이지(`KakaoRedirectPage`)에서 요청 성공/실패에 따라 로그인 처리 or 간편 회원가입 페이지로 이동된다.

 

`handleSignInKakao`를 보면 일단 간편 로그인을 먼저 하고, 그 다음 `data.user.createdAt`과 `data.user.updatedAt`의 일치 여부에 따라 로그인 or 회원가입을 분기 처리한다.

 

이렇게 한 이유는 어차피 간편 로그인 요청 응답(=`user`)을 기반으로

 

1. 로그인을 그대로 진행하거나,

2. 간편 회원가입 페이지로 이동시켜 닉네임만 변경하도록 해야 하기 때문이었다.

(참고로 닉네임은 간편 로그인 성공 시 임시 닉네임이 생성되었기 때문에, 닉네임 여부로 회원가입 여부를 판단할 수는 없었다)

 

특히 `user.createdAt !== user.updatedAt` 조건문을 추가하기 전에는 이미 가입된 카카오 계정도 간편 회원가입 페이지에 접근되는 문제가 발생했었다.

간편 로그인 여부는 user 데이터 여부로 판단할 수 있어도, 간편 회원가입 여부를 판단할 로직이 없었던 탓이다.

 

그래서 간편 회원가입 시 닉네임을 변경하면 `user.updatedAt`이 갱신되므로 `user.createdAt`과 달라진다는 점을 이용했고,

결과적으로 기존 가입 유저는 간편 회원가입 버튼을 눌러도 바로 간편 로그인이 진행되도록 UX를 개선할 수 있었다.

 

사실 이건 동료 개발자분이 코드 리뷰 때 알려주신 방법이다. 이 자리를 빌어 다시 한 번 감사드립니다(__)🙏👍

 

 

3. 간편 회원가입 페이지에서 '회원 정보 수정' api 이용

export default function KakaoSignUpPage() {
  // ...

  const onSubmit = async (data: KakaoSignUpRequest) => {
    const payload = {
      nickname: data.nickname,
    };

    try {
      await axiosInstance.patch('/user', payload);  // 기존 user 데이터를 patch(수정)하는 것으로 간편 회원가입 완료 처리 
      const res = await axiosInstance('/user');
      const user = res.data;

      // ...
    }

 

비록 간편 회원가입 api는 없었지만 '회원 정보 수정' api는 있는 상황이었어서,

간편 회원가입 페이지에서 기존 유저를 조회/수정/삭제할 수 있는 `/user` 엔드포인트에 `patch` 요청으로 입력된 닉네임만 전달하여 간편 회원가입을 완료시켰다.

+ 이때 `/user`에 patch 요청을 보내려면 권한이 필요했어서 axios interceptor의 액세스 토큰 자동 포함/갱신 로직을 활용했다.

 


 

이렇게 '간편 로그인' api와 '회원 정보 수정' api를 활용해서 간편 회원가입 api 없는 간편 회원가입 기능을 구현해보았다.

 

'React.js' 카테고리의 다른 글

[React.js+Vite] `manualChunks` 설정으로 초기 번들 크기 줄이기  (0) 2026.01.20
[React Query] queryKey vs mutationKey  (0) 2025.11.18
클라이언트 컴포넌트가 비동기 함수가 될 수 없는 이유  (4) 2025.08.13
react query(tanstack query)로 요청 최적화 해본 후기  (5) 2025.08.06
useEffect 안에 함수를 선언 및 호출하는 방식 vs 밖에서 선언하고, 안에서 호출하는 방식  (1) 2025.07.27
'React.js' 카테고리의 다른 글
  • [React.js+Vite] `manualChunks` 설정으로 초기 번들 크기 줄이기
  • [React Query] queryKey vs mutationKey
  • 클라이언트 컴포넌트가 비동기 함수가 될 수 없는 이유
  • react query(tanstack query)로 요청 최적화 해본 후기
쥬피썬더의노예
쥬피썬더의노예
오히려 좋아
  • 쥬피썬더의노예
    d.log
    쥬피썬더의노예
    글쓰기 관리
    • 분류 전체보기 (112)
      • JS (37)
      • TS (3)
      • WEB (10)
      • React.js (20)
      • Next.js (4)
      • tanstack query (2)
      • Node.js (2)
      • HTML (5)
      • CSS (13)
      • CS (1)
      • 에이전트 (1)
      • Git (4)
      • JAVA (0)
      • SQL (0)
      • db (0)
      • GSAP (0)
      • 자료구조 (1)
      • 알고리즘 (0)
      • ✨회고 (5)
      • 포꾸 (0)
      • 인터뷰 (0)
      • 개발일지 (0)
      • 일기 (1)
      • etc (3)
      • 정처기 실기 (0)
        • C (0)
        • Java (0)
        • Python (0)
      • fonts (0)
      • articles (0)
      • 도서 (0)
  • 인기 글

  • 태그

    SSR
    리팩토링
    SSG
    state
    React Query
    TypeScript
    폼
    클로저
    조합 패턴
    React
    자바스크립트
    유효성 검사
    HTML
    WEB
    CSR
    프론트엔드
    javascript
    zustand
    Til
    GIT
    useState
    css
    useEffect
    슬라이딩 윈도우
    Next.js
    React.JS
    안티그래비티
    리액트
    상태 관리
    아키텍처
  • 최근 글

  • 전체
    오늘
    어제
  • hELLO· Designed By정상우.v4.10.3
쥬피썬더의노예
간편 회원가입 api 없는 간편 회원가입 만들기 (feat. 카카오 간편 로그인)
상단으로

티스토리툴바