– Kakao 로그인 → Firebase Custom Token 변환 서버 이해하기
0️⃣ 이 글에서 다루는 전제
- Node.js 경험 ❌
- Firebase Cloud Functions 처음
- Kakao 로그인 + Firebase Auth 연동이 목표
- 이 파일 하나(index.js)가 서버의 전부
1️⃣ 이 파일(index.js)이 “무엇을 하는 파일인가?”
먼저 한 문장으로 요약하면 이거다.
index.js는
“카카오 로그인 결과를
Firebase가 신뢰할 수 있는 인증 토큰으로 변환해주는 서버 코드”다.
조금 더 풀면:
- iOS 앱에서 카카오 accessToken을 받아서
- 카카오 서버에 진짜 유효한 토큰인지 물어보고
- 문제가 없으면
- Firebase Custom Token을 만들어서
- 다시 iOS 앱에 돌려준다
👉 이 파일은 로그인 서버가 아니라
👉 **인증 토큰 변환기(adapter)**다.
2️⃣ 전체 코드 먼저 보기 (완성본)
📌 이 코드는 functions/index.js에 그대로 들어간다.
const functions = require("firebase-functions");
const admin = require("firebase-admin");
const axios = require("axios");
admin.initializeApp();
exports.kakaoCustomToken = functions.https.onRequest(async (req, res) => {
try {
// 1. iOS에서 전달한 Kakao accessToken
const { kakaoAccessToken } = req.body;
if (!kakaoAccessToken) {
return res.status(400).json({ error: "Missing kakaoAccessToken" });
}
// 2. Kakao API 호출 → 토큰 검증 + 사용자 정보 조회
const kakaoResponse = await axios.get(
"https://kapi.kakao.com/v2/user/me",
{
headers: {
Authorization: `Bearer ${kakaoAccessToken}`,
},
}
);
// 3. Kakao userId 추출
const kakaoUserId = kakaoResponse.data.id;
if (!kakaoUserId) {
return res.status(401).json({ error: "Invalid Kakao token" });
}
// 4. Firebase에서 사용할 uid 생성
const uid = `kakao:${kakaoUserId}`;
// 5. Firebase Custom Token 생성
const customToken = await admin.auth().createCustomToken(uid, {
provider: "KAKAO",
});
// 6. iOS 앱으로 Custom Token 반환
return res.json({ customToken });
} catch (error) {
console.error(error);
return res.status(500).json({ error: "Internal Server Error" });
}
});
3️⃣ Node.js를 전혀 모른다면, 이것부터 이해하면 된다
3-1. require는 뭐야?
const axios = require("axios");
- Swift의 import와 같은 개념
- “이 파일에서 axios라는 라이브러리를 쓰겠다”
3-2. 이 파일은 “서버”다
functions.https.onRequest((req, res) => { ... })
이 한 줄이 의미하는 건:
- HTTP 요청을 받는 서버 함수
- iOS에서 URL로 호출 가능
- req = 요청 (Request)
- res = 응답 (Response)
Swift로 비유하면:
func handleRequest(request) -> Response
3-3. async / await는 왜 쓰나?
exports.kakaoCustomToken = async (req, res) => { ... }
- 네트워크 요청(Kakao API)은 시간이 걸린다
- await는 “이 작업이 끝날 때까지 기다려라”는 뜻
Swift의:
async / await
와 개념적으로 거의 동일하다.
4️⃣ 코드 한 줄씩, “왜 이렇게 썼는지” 설명
① Firebase & 라이브러리 초기화
const functions = require("firebase-functions");
const admin = require("firebase-admin");
const axios = require("axios");
admin.initializeApp();
왜 필요한가?
- firebase-functions
→ Cloud Functions에서 서버 함수를 만들기 위해 필요 - firebase-admin
→ Custom Token을 만들 수 있는 유일한 SDK
→ 클라이언트(iOS)에서는 절대 만들 수 없음
(Firebase 공식 문서 근거) - axios
→ Node.js에서 HTTP API를 호출하기 위한 라이브러리
→ Kakao API(/v2/user/me) 호출용
(카카오 공식/커뮤니티 예제 다수에서 사용)
② HTTP 엔드포인트 생성
exports.kakaoCustomToken = functions.https.onRequest(...)
이 한 줄로:
- Firebase가 서버를 직접 띄워줌
- 우리가 포트/서버 설정할 필요 ❌
- 함수 이름이 곧 API endpoint가 됨
예:
https://us-central1-프로젝트ID.cloudfunctions.net/kakaoCustomToken
👉 Express의 app.post() 역할을 Firebase가 대신해준다.
③ iOS에서 accessToken 받기
const { kakaoAccessToken } = req.body;
- iOS 앱에서 JSON body로 전달
- 예:
{
"kakaoAccessToken": "eyJhbGciOi..."
}
왜 body로 받나?
- URL 쿼리보다 보안적으로 낫다
- REST API 표준 패턴
④ accessToken이 없으면 바로 종료
if (!kakaoAccessToken) {
return res.status(400).json({ error: "Missing kakaoAccessToken" });
}
왜 이렇게 빨리 종료하나?
- 서버는 불필요한 작업을 빨리 중단하는 게 좋다
- 잘못된 요청은 400 Bad Request가 REST 표준
⑤ Kakao API 호출 (핵심)
const kakaoResponse = await axios.get(
"https://kapi.kakao.com/v2/user/me",
{
headers: {
Authorization: `Bearer ${kakaoAccessToken}`,
},
}
);
이 코드의 의미
- 카카오 서버에 직접 묻는다:
- “이 토큰, 진짜 네가 발급한 거 맞아?”
- 응답이 온다면:
- 토큰 유효
- 사용자 정보 포함
⑥ Kakao userId 추출
const kakaoUserId = kakaoResponse.data.id;
- id는 카카오 계정의 고유 식별자
- 이메일은 바뀔 수 있어도 id는 바뀌지 않음
👉 Firebase UID로 쓰기에 가장 적합
⑦ Firebase UID 설계
const uid = `kakao:${kakaoUserId}`;
왜 이렇게 만들었나?
- provider prefix를 붙이면:
- google / apple / naver 확장 쉬움
- UID 충돌 방지
- 나중에 디버깅 쉬움
이건 Firebase Custom Auth에서 실무적으로 가장 많이 쓰이는 패턴
⑧ Custom Token 생성
const customToken = await admin.auth().createCustomToken(uid, {
provider: "KAKAO",
});
이게 핵심 중의 핵심
- Firebase는 이 토큰만 신뢰한다
- 이 토큰으로만:
Auth.auth().signIn(withCustomToken: customToken)
⑨ iOS로 응답 반환
return res.json({ customToken });
- 서버의 역할은 여기서 끝
- 로그인 행위는 iOS가 담당
👉 서버는 “인증 판단자”,
👉 클라이언트는 “로그인 실행자”
5️⃣ 이 파일에서 구현한 책임 정리
이 index.js는 딱 이것만 한다:
- Kakao 토큰을 받는다
- Kakao 서버에 검증을 요청한다
- Firebase용 토큰으로 변환한다
- 결과를 반환한다
❌ 세션 관리 안 함
❌ 사용자 프로필 저장 안 함
❌ DB 접근 안 함
→ 책임을 최소화했기 때문에 안전하고 확장 가능
6️⃣ 로직 실행 순서 한 번에 보기
iOS 앱
└─ Kakao SDK 로그인
↓ accessToken
Firebase Functions (index.js)
├─ 토큰 존재 확인
├─ Kakao API (/v2/user/me) 호출
├─ userId 추출
├─ Firebase Custom Token 생성
└─ customToken 반환
iOS 앱
└─ signInWithCustomToken
Firebase Cloud Functions index.js 구현 시 참고한 코드와 출처 정리
이 글에서 구현한 functions/index.js 코드는
완전히 처음부터 창작한 코드가 아니라,
공식 문서 + 실제 사용 사례 + 커뮤니티 예제를 참고해
내 목적(iOS + Kakao + Firebase Auth)에 맞게 재구성한 결과물이다.
아래는 실제로 참고한 대표적인 코드/자료들과,
그중에서 무엇을 가져오고 무엇을 버렸는지에 대한 정리다.
1️⃣ Firebase 공식 문서 – Custom Token 생성 (가장 핵심 근거)
📌 출처
- Firebase 공식 문서
“Authenticate using custom tokens”
https://firebase.google.com/docs/auth/admin/create-custom-tokens
📌 원본 예제 코드 (공식)
admin.auth().createCustomToken(uid)
.then((customToken) => {
// Send token back to client
});
📌 우리가 참고한 부분
- firebase-admin SDK에서
- Custom Token은 반드시 서버에서 생성해야 한다
- 클라이언트는 signInWithCustomToken으로 로그인
📌 우리가 변형한 부분
- 단순 예제 → Kakao userId 기반 uid 생성
- Custom claim에 { provider: "KAKAO" } 추가
- HTTP Function으로 감싸 iOS에서 호출 가능하게 구성
👉 이 문서가 index.js의 “존재 이유” 자체를 결정함
2️⃣ Kakao API 공식 문서 – 사용자 정보 조회 (/v2/user/me)
📌 출처
- Kakao Developers 공식 문서
“사용자 정보 가져오기”
https://developers.kakao.com/docs/latest/ko/kakaologin/rest-api#req-user-info
📌 원본 API 사용 방식
GET https://kapi.kakao.com/v2/user/me
Authorization: Bearer {ACCESS_TOKEN}
📌 우리가 참고한 부분
- accessToken을 Authorization Bearer 헤더로 전달
- /v2/user/me 응답에서 id가 고유 사용자 식별자라는 점
📌 우리가 변형한 부분
- 웹 서버가 아닌 Firebase Functions에서 호출
- 세션 저장 ❌
- DB 저장 ❌
→ “검증 + 식별”만 수행
👉 Kakao 로그인에서 **유일하게 변하지 않는 값은 id**라는 판단의 근거
3️⃣ Node.js + Kakao 로그인 커뮤니티 예제 (axios 사용 근거)
📌 출처 (네가 실제로 참고했던 글)
- velog
[Node.js] kakao login api 가져오기
https://velog.io/@nara7875/Node.js-kakao-login-api-%EA%B0%80%EC%A0%B8%EC%98%A4%EA%B8%B0
📌 원본 코드의 핵심 부분 (요지)
axios({
method: "GET",
url: "https://kapi.kakao.com/v2/user/me",
headers: {
Authorization: `Bearer ${accessToken}`,
},
});
📌 우리가 참고한 부분
- Node.js 환경에서 Kakao API 호출 시 axios 사용
- accessToken 검증을 Kakao 서버에 위임하는 구조
📌 우리가 버린 부분
- Express 서버 구성
- /auth/kakao, /callback 라우팅
- 세션(express-session)
- 웹 페이지 렌더링
👉 “Kakao API 호출 방식만 참고하고, 서버 구조는 전부 버림”
4️⃣ Firebase Cloud Functions 공식 예제 – HTTPS Function 형태
📌 출처
- Firebase 공식 문서
“HTTP-triggered functions”
https://firebase.google.com/docs/functions/http-events
📌 원본 예제 코드
exports.helloWorld = functions.https.onRequest((req, res) => {
res.send("Hello from Firebase!");
});
📌 우리가 참고한 부분
- functions.https.onRequest 형태
- Express 없이도 HTTP API를 만들 수 있다는 점
📌 우리가 변형한 부분
- 단순 응답 → 인증 로직
- req.body 파싱
- status code + JSON 응답
5️⃣ Firebase + 외부 OAuth 연동 실무 패턴 (Custom Token 전략)
📌 출처
- Firebase GitHub / StackOverflow / 커뮤니티 전반
- 검색 키워드:
- firebase custom token oauth
- firebase kakao login custom token
- firebase external auth custom token
대표적인 패턴 요약:
Client (SNS login)
→ Server (verify token)
→ Firebase Admin (createCustomToken)
→ Client (signInWithCustomToken)
📌 우리가 그대로 따른 부분
- 외부 SNS 로그인 → Custom Token 변환
- 서버는 인증 판단만, 로그인 상태 관리는 Firebase에 위임
📌 우리가 단순화한 부분
- 사용자 profile DB 저장 ❌
- 신규/기존 유저 분기 ❌
→ Auth 책임만 수행
👉 실무에서 가장 많이 쓰이는 “얇은 인증 서버” 패턴
'PulseBoard' 카테고리의 다른 글
| 🚀 axios 설치와 역할 - 서버에서 토큰 검증이 필요한 이유! (0) | 2025.12.26 |
|---|---|
| Firebase Authentication의 OpenID Connect를 쓰지 않고Cloud Functions + Custom Token으로 Kakao 로그인을 구현한 이유 (1) | 2025.12.25 |
| Firebase - Functions 의 Index.js 역할 (0) | 2025.12.24 |
| Firebase Functions 초기 환경 설정 해보기 (0) | 2025.12.24 |
| 🔥 Firebase Functions 시작하다가 npm 에러와 경고를 만났을 때 정리 (0) | 2025.12.24 |