Pause & Play
[FastAPI] 카카오 소셜 로그인 백엔드 구현하기 (OAuth 2.0 & Azure 배포) 본문
최근 프로젝트를 진행하며 FastAPI 환경에서 카카오 소셜 로그인을 구현할 기회를 가지게 되었다. 소셜 로그인 구현이 처음 해보았을 때, 좀 헷갈렸어서... 이렇게 정리를 하는 시간을 가지게 되었다.
구현 성공을 기념으로 어떻게 진행하면 좋을지 정리해보도록 하겠다.
1. 전체적인 로그인 흐름 이해하기
본격적으로 코드를 작성하기 전에 카카오 로그인 API의 인증 흐름을 이해하는 게 중요하다.
- Frontend: 사용자가 '카카오 로그인' 버튼 클릭 → 카카오 인가 코드 요청
- Kakao API: 사용자 인증 후 인가 코드(Authorization Code)를 Backend로 전달
- Backend: 전달받은 인가 코드로 카카오에 Access Token 요청
- Backend: 토큰을 이용해 사용자 정보(이메일, 닉네임 등) 획득
- Backend: 우리 서비스의 자체 JWT 발급 또는 로그인 처리
Note: 나 같은 경우는 프론트에서 인가코드를 받아 백엔드로 전달해주는 흐름이 아닌 프론트에서 엑세스 토큰을 발급받을 줄 알아서 처음 프론트와의 연결에서 살짝 문제가 생겼었다.. 그래서 개발 시작 전 Swagger나 Postman을 활용해 요청(Request)과 응답(Response)의 데이터 타입, 필수값 여부, 에러 코드 규격을 먼저 확정하는 'API-First' 접근 방식을 지향하게 되었다.
JWT(JSON Web Token)란?
로그인에 성공한 사용자에게 "당신은 인증된 사용자입니다"라고 증명서를 끊어준다고 생각하면 이해하기 쉽다. 토큰을 받아오면 그 토큰의 유효성만 검증하면 되는 형식이기 때문에 서버 부하를 줄일 수 있어 가장 많이 쓰인다.
- Header: 토큰의 타입(JWT)과 사용 중인 해시 알고리즘 정보.
- Payload: 사용자 ID, 토큰 만료 시간 등 실제 전달하려는 정보(Claim).
- Signature: 서버만 알고 있는 'Secret Key'로 암호화된 서명. (변조 확인용)
2. 사전 준비
카카오 디벨로퍼스에서 다음 설정을 완료한다. (메인화면 > 앱 > 앱생성 클릭)


- 내 애플리케이션 등록
- Platform: 웹 서비스 URL 등록 (예: http://localhost:8000)
- Redirect URI: 인가 코드를 받을 주소 등록 (예: /auth/kakao/callback)
- Client Secret: 보안을 위해 활성화 권장
REST API 방식을 선택한 이유?
백엔드에서 server to server로 통신을 하기 때문에 좀 더 토큰 관리의 안정성이 보장되기도 하고, 추후 플랫폼 확장성과 비즈니스 로직을 생각했을 때도 REST API가 적합하다는 판단을 내렸다.
3. FastAPI 코드 구현
기본적으로 팀 프로젝트를 진행하여 깃허브에 올릴 경우 보안상의 문제로 .env 파일을 활용한다.
api키와 리디엑트 uri 만 있어도 되지만, 나는 인가 코드를 가로채는 공격을 방지하기 위해 서버 사이드에서 client_secret을 사용해 검증력을 높였다.
[.env]
KAKAO_REST_API_KEY=<사용한 RESTAPI 키>
KAKAO_USER_INFO_URL=https://kapi.kakao.com/v2/user/me
KAKAO_REDIRECT_URI=<리디렉트 URI 주소>
KAKAO_CLIENT_SECRET=<클라이언트 시크릿 키>
[Backend Logic]
from fastapi import APIRouter, HTTPException, Depends
from sqlalchemy.orm import Session
import httpx
from src.app.core.config import settings
from src.app.core.security import create_access_token
from src.app.core.database import get_db
from src.app.models.user import User
from src.app.schemas.auth import LoginRequest
router = APIRouter()
@router.post("/login")
async def kakao_login(request: LoginRequest, db: Session = Depends(get_db)):
"""
카카오톡을 이용한 로그인 프로세스를 진행합니다.
"""
# 1. 인가 코드로 카카오 토큰 발급 요청 (POST 방식)
token_url = "https://kauth.kakao.com/oauth/token"
token_data = {
"grant_type": "authorization_code",
"client_id": settings.KAKAO_REST_API_KEY,
"redirect_uri": settings.KAKAO_REDIRECT_URI,
"code": request.accessToken, # 프론트에서 받은 인가코드
"client_secret": settings.KAKAO_CLIENT_SECRET,
}
async with httpx.AsyncClient() as client:
token_resp = await client.post(token_url, data=token_data)
if token_resp.status_code != 200:
raise HTTPException(status_code=401, detail="카카오 토큰 발급 실패")
kakao_tokens = token_resp.json()
real_access_token = kakao_tokens.get("access_token")
# 2. 받은 진짜 access_token으로 사용자 정보 가져오기
user_info_url = settings.KAKAO_USER_INFO_URL
headers = {
"Authorization": f"Bearer {real_access_token}",
"Content-type": "application/x-www-form-urlencoded;charset=utf-8",
}
user_resp = await client.post(user_info_url, headers=headers)
if user_resp.status_code != 200:
raise HTTPException(status_code=401, detail="사용자 정보 조회 실패")
kakao_user = user_resp.json()
kakao_id = str(kakao_user.get("id"))
# 3. DB 조회 및 회원가입 로직
user = db.query(User).filter(User.social_id == kakao_id).first()
if not user:
temp_nickname = f"BINGO_{kakao_id[:5]}"
user = User(social_id=kakao_id, social_provider="KAKAO", nickname=temp_nickname)
db.add(user)
db.commit()
db.refresh(user)
# 4. 우리 서비스 전용 JWT 발급
my_token = create_access_token(data={"sub": str(user.id)})
is_required_nickname = user.nickname.startswith("BINGO_")
return {
"status": "success",
"message": "로그인 성공",
"data": {
"accessToken": my_token,
"is_required_nickname": is_required_nickname,
"user": {"id": user.id, "nickname": user.nickname},
},
}
4. Azure 배포 및 CORS 설정
코드를 다 짰다면 이제 실제 서버에 올려서 프론트엔드와 연결할 차례다. 우리는 Azure 인프라를 활용해 환경을 구축하였다.
1. 인프라 구성

- Frontend: Azure Static Web Apps (SWA)를 이용해 배포했다. SWA는 GitHub 액션과 연동되어 push만 하면 자동으로 배포되는 형식으로 정말 편하다.
- Backend: Azure App Service를 사용했다.
[배포 tip] Azure Static Web Apps 생성 및 GitHub 연동

1. 빌드 세부 설정 (Build Details)
연동 후 하단에 나타나는 빌드 상세 설정도 꼼꼼히 봐야 한다. 이 부분이 틀리면 "배포는 성공했는데 화면이 안 떠요" 하는 상황이 발생한다.
- Build Presets: 프론트엔드 프레임워크(React, Vue, Next.js 등)에 맞춰 선택한다.
- App location: 소스 코드가 있는 루트 경로 (보통 /)
- Output location: 빌드 결과물이 생기는 폴더명. 프레임워크마다 dist인지 build인지 다르므로 본인의 프로젝트 구조를 꼭 확인해야 한다. (예: Vite는 보통 dist, React 기본 설정은 build)

2. 배포 권한 설정 (Deployment configuration)
리소스를 처음 생성할 때 가장 중요한 부분이다.
- GitHub 선택 필수: 캡처 화면처럼 Deployment authorization policy에서 GitHub를 선택해야 한다. 그래야 GitHub Repository의 코드가 수정될 때마다 Azure가 알아서 빌드하고 배포하는 자동화(CI/CD)가 완성된다.
- 권한 승인: GitHub를 선택하면 내 계정을 연동하라는 창이 뜨는데, 거기서 대상 리포지토리를 정확히 골라주면 된다.
2. 프론트엔드와 연결 시 주의할 점 (CORS 설정)
서로 다른 도메인(SWA 주소와 App Service 주소) 간에 통신을 하려면 FastAPI에서 CORS(Cross-Origin Resource Sharing) 설정을 반드시 해주어야 한다.
CORS(Cross-Origin Resource Sharing)란?
브라우저에서 보안을 위해 출처가 다른 서버로의 요청을 막는 정책이다. FastAPI에서는 CORSMiddleware를 통해 허용할 프론트엔드 주소를 등록해주어야 한다.
from fastapi.middleware.cors import CORSMiddleware
app.add_middleware(
CORSMiddleware,
allow_origins=["https://your-static-web-app-url.azurestaticapps.net"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
또한 Azure App Service의 설정(Configuration) 메뉴에서 환경 변수를 등록해주는 것도 잊지 말아야 한다.

이렇게 연결 후 테스트를 하면 로그인이 성공하는 걸 확인할 수 있다.
처음에는 프론트엔드에서 넘겨주는 값이 인가 코드인지 엑세스 토큰인지 헷갈려 커뮤니케이션 미스가 있기도 했지만, 덕분에 OAuth 2.0의 흐름을 정확히 머릿속에 새길 수 있었다. 역시 개발은 직접 삽질해보고 구현해봐야 가장 빠르게 배우는 것 같다...
Azure 배포 환경에서의 설정이나 CORS 이슈 등 제가 겪은 과정이 소셜 로그인을 처음 구현하시는 분들께 조금이나마 이정표가 되길 바란다!!
'개발' 카테고리의 다른 글
| GitHub - 협업 편 (1) | 2026.04.17 |
|---|