프론트엔드, AI와 함께 소셜 로그인 정복기 (백엔드 코드 분석부터 구현까지)
프론트엔드, AI와 함께 소셜 로그인 정복기 (백엔드 코드 분석부터 구현까지)
부제: “이 버튼, 어떻게 살리죠?” 백엔드 변경 없이 카카오 로그인 붙인 이야기
“카카오 로그인 버튼을 만들어야 하는데, 어디서부터 시작해야 할지 막막하다.”
프론트엔드 개발자라면 한 번쯤은 마주했을 고민입니다. 특히 백엔드 API 명세가 불완전하거나, 당장 코드를 수정할 수 없는 상황이라면 문제는 더 복잡해집니다.
최근 저도 비슷한 상황에 놓였습니다. 백엔드 팀으로부터 카카오 소셜 로그인 코드를 전달받았고, 프론트엔드에서 이를 연결해야 하는 미션을 받았죠. 막막함 속에서 저는 AI 페어 프로그래밍 툴인 Cursor에게 도움을 요청했습니다.
이 글은 AI와 함께 백엔드 코드를 분석하고, 허들을 발견하고, 결국 백엔드 수정 없이 프론트엔드 기능을 구현해낸 한 편의 현실적인 고군분투 기록입니다. 저와 같은 고민을 하고 계신 분들께 실용적인 나침반이 되기를 바랍니다.
1장: AI, 백엔드 코드의 탐정이 되다
첫 번째 임무는 명확했습니다. “프론트엔드 개발자 관점에서 이 코드들을 분석하고, 부족한 점이 있는지 알려줘.”
AI는 순식간에 Controller, Service, Repository로 분리된 코드 구조를 파악하고, 전체적인 OAuth 2.0 인증 흐름을 요약해주었습니다.
- 로그인 시작: 프론트엔드 → 백엔드 카카오 로그인 URL 요청
- 카카오 인증: 백엔드 → 카카오 인증 페이지로 리다이렉트
- 콜백 처리: 카카오 → 백엔드 콜백 URL로
인증 code와 함께 리다이렉트 - 토큰 교환 및 사용자 처리: 백엔드,
code로access_token을 받고 사용자 정보 조회 - 회원가입/로그인: 신규 유저면 DB에 생성
- 세션 생성 및 응답: 서버 세션에 사용자 정보 저장 후, JSON 데이터 응답
전체적인 구조는 훌륭했지만, AI 탐정은 프론트엔드와의 연동 과정에서 발생할 수 있는 네 가지 결정적인 허들을 발견했습니다.
2장: 네 개의 허들 - AI의 날카로운 지적
🎯 허들 1: 로그인 성공 후 마주하는 ‘JSON의 벽’
가장 치명적인 문제였습니다. 로그인에 성공한 사용자는 프론트엔드 화면으로 돌아오는 대신, 쌩뚱맞은 JSON 데이터를 마주하게 됩니다.
// Omechu-server-dh/backend/src/controllers/kakao.controller.js:50res.status(StatusCodes.OK).success({ id: user.id.toString(), email: user.email,});- 문제점: 사용자 경험(UX)에 치명적입니다. 사용자는 로그인이 끝난 뒤 뭘 해야 할지 알 수 없습니다.
- 이상적인 해결책: 백엔드에서 프론트엔드 페이지로 리다이렉트 시켜주는 것입니다.
// res.redirect('https://your-frontend-domain.com/');
🎯 허들 2: 보안의 구멍, ‘state’ 파라미터의 부재
현재 로직에는 CSRF(Cross-Site Request Forgery) 공격을 방어하는 데 필수적인 state 파라미터가 누락되어 있었습니다.
- 문제점: 악의적인 사이트가 우리 사이트인 척 로그인 요청을 보내 사용자의 계정을 탈취할 위험이 있습니다.
- 이상적인 해결책: 로그인 시작 시, 백엔드가 예측 불가능한
state값을 생성해 세션에 저장하고, 카카오 인증 요청 시 함께 보냅니다. 콜백 시, 돌아온state값과 세션의 값을 비교하여 일치할 때만 로그인을 진행해야 합니다.
🎯 허들 3: 불친절한 에러 처리
next(err)를 통한 에러 처리는 서버에는 기록을 남기지만, 사용자에게는 그저 ‘서버 에러’ 페이지만 보여줄 뿐입니다.
- 문제점: 유효하지 않은
code가 전달되거나 카카오 API 서버에 문제가 생기는 등 다양한 에러 상황을 사용자가 알 수 없습니다. - 이상적인 해결책: 에러 종류를 구분하여, “카카오 인증에 실패했습니다.” 와 같은 메시지와 함께 프론트엔드의 특정 에러 페이지로 리다이렉트 해주는 것이 좋습니다.
🎯 허들 4: 유령 DTO의 정체
kakao.dto.js 파일은 요청 body에서 code를 받도록 설계되어 있었지만, 정작 컨트롤러는 query string에서 code를 받고 있었습니다. 사용되지 않는 이 DTO는 코드의 혼란을 야기할 수 있었습니다.
3장: “백엔드 없이, 갑시다” - 프론트엔드의 반격
백엔드 팀과 위 이슈들을 논의하여 개선하는 것이 정석이지만, 때로는 비즈니스 속도에 맞춰 프론트엔드에서 먼저 움직여야 할 때도 있습니다.
“백엔드 코드를 지금 바꾸지 않아도 전부 기능하도록 할 수는 있는거야!?”
AI의 대답은 “Yes” 였습니다. ‘JSON의 벽’ 문제를 우회하는 똑똑한 전략과 함께 말이죠.
- 로그인 시작: 카카오 로그인 버튼은 백엔드 API를 호출하는 단순한 링크(
<a>태그) 역할을 합니다. - 로그인 후 상태 동기화: 사용자는 로그인 후 JSON 페이지에 잠시 머무르지만, 서버에는 이미 세션이 생성된 상태입니다. 사용자가 다시 우리 앱으로 돌아왔을 때, 앱이 로드되는 순간 서버에 “나 지금 로그인 되어 있나요?”라고 물어봐서 프론트엔드의 로그인 상태를 강제로 동기화하는 것입니다.
4장: 코드 레벨 구현 - 버튼에 생명을 불어넣다
이 전략을 바탕으로 실제 코드를 작성했습니다.
STEP 1: 카카오 로그인 버튼에 링크 연결하기
sign-in 페이지의 버튼을 백엔드 로그인 API를 직접 호출하는 <a> 태그로 변경합니다.
<a href={`${process.env.NEXT_PUBLIC_API_URL || "http://localhost:3000"}/api/auth/kakao/redirect`} className="flex h-14 w-full items-center justify-center gap-2 rounded-md bg-[#FEE500] p-2 text-lg font-medium text-black transition-colors hover:bg-[#f3da00] active:bg-[#e0c900]"> <Image src="/kakao/kakao.svg" alt="카카오 아이콘" width={24} height={24} /> 카카오 로그인</a>Link 컴포넌트가 아닌 a 태그를 쓴 이유는 우리 앱 내부 라우팅이 아닌, 외부 백엔드 서버로 직접 요청을 보내야 하기 때문입니다.
STEP 2: 앱 로드 시, 세션 상태 동기화하기
사용자가 사이트로 돌아왔을 때 로그인 상태를 확인하고 프론트엔드 상태(Zustand 스토어)를 업데이트하는 로직이 필요합니다.
먼저, 세션 정보를 가져오는 API 훅을 react-query를 이용해 만듭니다.
// 세션 확인을 위한 useQuery 훅export const useCheckSessionQuery = () => { return useQuery({ queryKey: ['session'], queryFn: checkSession, // '/auth/session' 같은 API를 호출하는 함수 retry: false, refetchOnWindowFocus: false, });};그리고 앱의 최상단 레이아웃 컴포넌트에서 이 훅을 사용해, 앱이 로드될 때마다 로그인 상태를 확인합니다.
"use client";
import { useEffect } from "react";import { useRouter } from "next/navigation";import { useCheckSessionQuery } from "@/lib/hooks/useAuth";import { useAuthStore } from "@/auth/store";
export default function ClientLayout({ children }: { children: React.ReactNode }) { const router = useRouter(); const { data: sessionUser, isSuccess, isError } = useCheckSessionQuery(); const { user, login: loginAction } = useAuthStore();
useEffect(() => { // 1. 프론트에 이미 로그인 정보가 있거나, API가 실패하면 아무것도 안함 if (user || isError) { return; }
// 2. 세션 확인 API가 성공했고, 사용자 정보가 있다면 if (isSuccess && sessionUser) { // 3. Zustand 같은 프론트엔드 상태 저장소에 유저 정보 업데이트 loginAction({ user: sessionUser, /* ... */ }); console.log("Session restored:", sessionUser);
// 4. 온보딩 페이지나 메인 페이지로 이동 if (!sessionUser.nickname) { router.push("/onboarding/1"); } else { router.push("/mainpage"); } } }, [isSuccess, isError, sessionUser, user, loginAction, router]);
return <>{children}</>;}이 로직 덕분에 사용자는 카카오 로그인 후 잠시 JSON 페이지를 보게 되더라도, 다시 우리 사이트로 돌아오면 완벽하게 로그인된 상태로 서비스를 이용할 수 있게 됩니다.
여정을 마치며: 실용주의적 승리
이번 경험을 통해, 완벽한 환경이 아니더라도 문제를 깊이 분석하고 창의적인 해결책을 찾는다면 길은 반드시 있다는 것을 배웠습니다. AI는 이 과정에서 단순한 코드 생성기를 넘어, 전체 구조를 파악하고 잠재적 위험을 경고하며 대안까지 제시하는 훌륭한 파트너가 되어주었습니다.
물론, 이 방법은 어디까지나 ‘우회로’입니다. 장기적으로는 백엔드 팀과 협력하여 리다이렉트, state 파라미터 적용 등 근본적인 개선을 해나가는 것이 정답일 것입니다.
하지만 당장 눈앞의 문제를 해결해야 하는 프론트엔드 개발자에게, 때로는 이런 실용주의적 접근이 가장 빛나는 해결책이 될 수 있습니다. 여러분의 소셜 로그인 여정에 이 글이 작은 힌트가 되었기를 바랍니다.
💬 댓글