← 블로그 목록
카카오 로그인OAuth소셜 로그인인증웹 개발

카카오 로그인 붙이기: 준비물과 막히는 지점 5가지

카카오 로그인의 전체 흐름부터 리다이렉트 URI 불일치, 이메일이 안 오는 경우, state 검증 누락까지 실제로 막히는 지점을 정리했습니다.

Vibeollio 팀-

붙이기 전에 알아둘 전체 그림

카카오 로그인은 "버튼 하나 붙이면 끝"처럼 보이지만 실제로는 우리 서버가 중간에 껴야 합니다. 이 구조를 모르고 시작하면 어디서 막힌 건지 판단이 안 됩니다.

흐름은 이렇습니다.

  1. 사용자가 로그인 버튼을 누르면 카카오 인증 화면으로 보냅니다
  2. 사용자가 동의하면 카카오가 우리가 지정해둔 주소로 인가 코드를 붙여 돌려보냅니다
  3. 우리 서버가 그 코드를 카카오에 보내 액세스 토큰으로 교환합니다
  4. 그 토큰으로 사용자 정보를 조회합니다
  5. 그 정보로 우리 서비스의 로그인 상태를 만듭니다

3번이 핵심입니다. 코드를 토큰으로 바꾸는 요청에는 앱의 비밀 키가 들어가므로 반드시 서버에서 해야 합니다. 브라우저에서 처리하는 예제를 따라 하면 키가 그대로 노출됩니다.

그리고 5번을 빠뜨리는 경우가 많습니다. 카카오는 "이 사람이 맞다"까지만 확인해줍니다. 그 뒤로 로그인 상태를 유지하는 건 우리 몫입니다.

준비물

개발자 사이트에서 앱을 만들고 다음을 확보해야 합니다.

  • 앱 키 — 서버에서 쓰는 키와 클라이언트용 키가 구분돼 있습니다. 서버용 키는 절대 브라우저로 나가면 안 됩니다.
  • 리다이렉트 URI 등록 — 2번에서 돌아올 주소입니다.
  • 동의 항목 설정 — 닉네임, 프로필 사진, 이메일 중 무엇을 받을지 정합니다.
  • 플랫폼 등록 — 웹이라면 사이트 도메인을 등록합니다.

콘솔 화면 구성과 정책은 바뀔 수 있으니 실제 항목 이름은 공식 문서를 확인하세요. 여기서는 어디서 막히는지에 집중합니다.

막히는 지점 1: 리다이렉트 URI 불일치

가장 흔하고, 가장 많은 시간을 잡아먹습니다. 등록해둔 주소와 요청에 넣은 주소가 문자 하나까지 정확히 같아야 합니다.

자주 어긋나는 것들입니다.

  • 끝 슬래시 유무 (/callback/callback/)
  • httphttps
  • 포트 번호 (localhost:3000localhost:3001)
  • www 유무

그리고 로컬 개발용과 운영용을 둘 다 등록해야 합니다. 로컬에서 되던 게 배포하면 안 되는 이유가 대개 이것입니다.

막히는 지점 2: 이메일이 안 올 수 있다

이메일을 사용자 식별에 쓰려고 설계했다가 여기서 막힙니다. 이메일은 항상 오는 값이 아닙니다.

  • 동의 항목이 선택으로 설정돼 있으면 사용자가 거부할 수 있습니다
  • 카카오 계정에 이메일이 등록돼 있지 않을 수 있습니다
  • 항목에 따라 추가 심사나 조건이 필요한 경우가 있습니다

그래서 이메일을 필수로 가정한 설계는 위험합니다. 사용자를 구분하는 기준은 카카오가 주는 고유 식별자로 잡고, 이메일은 있으면 저장하는 부가 정보로 다루세요.

CREATE TABLE users (
  id            uuid PRIMARY KEY DEFAULT gen_random_uuid(),
  kakao_id      text UNIQUE NOT NULL,   -- 식별 기준
  email         text,                   -- 없을 수 있다
  nickname      text,
  created_at    timestamptz NOT NULL DEFAULT now()
);

이메일이 없는 사용자를 어떻게 다룰지도 미리 정해두세요. 가입 후 따로 입력받을지, 없이도 쓰게 할지입니다.

막히는 지점 3: state 검증을 빠뜨린다

인증 요청을 보낼 때 무작위 문자열을 state 값으로 함께 보내고, 돌아왔을 때 같은 값인지 확인해야 합니다.

이걸 생략하면 공격자가 만든 인증 결과를 피해자의 브라우저에서 처리하게 만드는 공격이 가능해집니다. 예제 코드에 자주 빠져 있는 부분입니다.

// 보내기 전: 세션이나 쿠키에 저장해두고
const state = crypto.randomBytes(16).toString("hex");

// 돌아왔을 때: 반드시 비교
if (returnedState !== savedState) throw new Error("state mismatch");

막히는 지점 4: 로그인 이후를 안 만든다

토큰을 받아놓고 그걸 브라우저에 저장해 인증에 쓰는 구현을 종종 봅니다. 권장하지 않습니다.

카카오가 준 토큰은 카카오 API를 호출하기 위한 것이지 우리 서비스의 인증 수단이 아닙니다. 사용자 정보를 확인한 뒤에는 우리 서비스의 세션을 따로 발급하는 것이 맞습니다. 그래야 강제 로그아웃, 권한 관리, 만료 정책을 우리가 통제할 수 있습니다.

세션 쿠키에는 HttpOnly, Secure, SameSite를 빠짐없이 지정하세요.

막히는 지점 5: 연결 끊기와 탈퇴

만들 때는 잘 안 떠오르는데 나중에 반드시 필요해지는 부분입니다.

  • 사용자가 우리 서비스를 탈퇴하면 카카오 쪽 연결도 끊어줘야 합니다
  • 반대로 사용자가 카카오 설정에서 연결을 끊는 경우도 있습니다. 이 경우를 알림으로 받을 수 있는 기능이 제공되므로 처리 경로를 만들어두면 데이터가 어긋나지 않습니다

처음부터 여러 소셜 로그인을 붙여도 되나요?

권하지 않습니다. 하나를 제대로 끝낸 다음에 늘리는 편이 낫습니다. 다만 나중을 위해 테이블 설계는 미리 열어두세요. kakao_id 컬럼 하나를 두는 대신, 제공자와 식별자를 묶어 저장하는 별도 테이블로 두면 나중에 다른 로그인을 추가할 때 구조를 바꾸지 않아도 됩니다.

같은 사람이 다른 방법으로 로그인하면 어떻게 하나요?

이메일이 같다고 자동으로 합치는 건 위험합니다. 소셜 제공자가 이메일 소유를 검증했는지 보장할 수 없고, 계정 탈취 경로가 될 수 있습니다. 안전한 방식은 이미 로그인된 상태에서 다른 로그인 수단을 추가로 연결하게 하는 것입니다. 로그인 시점에 자동 병합하지 마세요.

테스트는 어떻게 하나요?

실제 카카오 계정으로 해야 합니다. 그래서 탈퇴와 재가입을 반복해서 확인하는 것이 중요합니다. 한 번 연결한 뒤에는 동의 화면이 생략되기 때문에, 처음 사용자가 보는 흐름을 다시 보려면 연결을 끊고 다시 시작해야 합니다. 이 과정을 안 거치면 "첫 사용자 경험"을 한 번도 확인하지 못한 채 배포하게 됩니다.

흐름을 이해하면 오류가 읽힌다

대부분의 실패는 위 다섯 지점 중 하나입니다. 어느 단계에서 멈췄는지만 알면 원인을 좁히기 쉽습니다. 인가 코드까지 왔는지, 토큰 교환에서 막혔는지, 사용자 정보는 받았는지를 단계별로 찍어보세요.

로그인이 붙은 프로젝트를 만들었다면 Vibeollio에 프로젝트 등록해서 공개해보세요. 실제로 여러 사람이 가입해보는 과정에서 혼자 테스트할 때 안 밟던 경로가 드러납니다.

카카오 로그인 붙이기: 준비물과 막히는 지점 5가지 | Vibeollio