# 카카오 소셜 로그인 구현 가이드 ## 목차 1. [개요](#1-개요) 2. [인증 흐름](#2-인증-흐름) 3. [User 모델 구조](#3-user-모델-구조) 4. [API 엔드포인트](#4-api-엔드포인트) 5. [환경 설정](#5-환경-설정) 6. [에러 처리](#6-에러-처리) --- ## 1. 개요 CastAD는 카카오 소셜 로그인만 지원하며, 인증 후 자체 JWT 토큰을 발급합니다. ### 인증 방식 | 항목 | 설명 | |------|------| | 소셜 로그인 | 카카오 OAuth 2.0 | | 자체 인증 | JWT (Access Token + Refresh Token) | | 카카오 토큰 저장 | X (1회 검증 후 폐기) | --- ## 2. 인증 흐름 ### 2.1 전체 흐름도 ``` ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ Client │ │ Backend │ │ Kakao │ │ DB │ └────┬────┘ └────┬────┘ └────┬────┘ └────┬────┘ │ │ │ │ │ 1. 로그인 요청 │ │ │ │──────────────>│ │ │ │ │ │ │ │ 2. 카카오 로그인 URL 반환 │ │ │<──────────────│ │ │ │ │ │ │ │ 3. 카카오 로그인 페이지로 이동 │ │ │──────────────────────────────>│ │ │ │ │ │ │ 4. 사용자 인증 후 code 반환 │ │ │<──────────────────────────────│ │ │ │ │ │ │ 5. code 전달 │ │ │ │──────────────>│ │ │ │ │ │ │ │ │ 6. code로 토큰 요청 │ │ │──────────────>│ │ │ │ │ │ │ │ 7. access_token 반환 │ │ │<──────────────│ │ │ │ │ │ │ │ 8. 사용자 정보 조회 │ │ │──────────────>│ │ │ │ │ │ │ │ 9. 사용자 정보 반환 │ │ │<──────────────│ │ │ │ │ │ │ │ 10. kakao_id로 회원 조회 │ │ │──────────────────────────────>│ │ │ │ │ │ │ 11. 회원 정보 반환 (없으면 생성) │ │ │<──────────────────────────────│ │ │ │ │ │ 12. 자체 JWT 발급 및 반환 │ │ │<──────────────│ │ │ │ │ │ │ ``` ### 2.2 단계별 설명 | 단계 | 설명 | 관련 API | |------|------|----------| | 1-2 | 클라이언트가 로그인 요청, 백엔드가 카카오 인증 URL 생성 | `GET /user/auth/kakao/login` | | 3-4 | 사용자가 카카오에서 로그인, 인가 코드(code) 발급 | 카카오 OAuth | | 5-9 | 백엔드가 code로 카카오 토큰/사용자정보 획득 | 카카오 API | | 10-11 | DB에서 회원 조회, 없으면 신규 가입 | 내부 처리 | | 12 | 자체 JWT 토큰 발급 후 클라이언트에 반환 | `POST /user/auth/kakao/callback` | --- ## 3. User 모델 구조 ### 3.1 테이블 스키마 ``` ┌─────────────────────────────────────────────────────────────┐ │ user │ ├─────────────────────┬───────────────┬───────────────────────┤ │ Column │ Type │ Description │ ├─────────────────────┼───────────────┼───────────────────────┤ │ id │ BIGINT (PK) │ 고유 식별자 (자동증가) │ │ kakao_id │ BIGINT (UQ) │ 카카오 회원번호 │ │ email │ VARCHAR(255) │ 이메일 (선택) │ │ nickname │ VARCHAR(100) │ 닉네임 (선택) │ │ profile_image_url │ VARCHAR(2048) │ 프로필 이미지 URL │ │ thumbnail_image_url │ VARCHAR(2048) │ 썸네일 이미지 URL │ │ is_active │ BOOLEAN │ 계정 활성화 상태 │ │ is_admin │ BOOLEAN │ 관리자 권한 │ │ last_login_at │ DATETIME │ 마지막 로그인 일시 │ │ created_at │ DATETIME │ 생성 일시 │ │ updated_at │ DATETIME │ 수정 일시 │ └─────────────────────┴───────────────┴───────────────────────┘ ``` ### 3.2 카카오 API 응답 매핑 ```json // 카카오 API 응답 예시 { "id": 1234567890, "kakao_account": { "email": "user@kakao.com", "profile": { "nickname": "홍길동", "profile_image_url": "https://k.kakaocdn.net/.../profile.jpg", "thumbnail_image_url": "https://k.kakaocdn.net/.../thumb.jpg" } } } ``` | User 필드 | 카카오 응답 경로 | |-----------|-----------------| | `kakao_id` | `id` | | `email` | `kakao_account.email` | | `nickname` | `kakao_account.profile.nickname` | | `profile_image_url` | `kakao_account.profile.profile_image_url` | | `thumbnail_image_url` | `kakao_account.profile.thumbnail_image_url` | --- ## 4. API 엔드포인트 ### 4.1 카카오 로그인 URL 요청 ``` GET /user/auth/kakao/login ``` **Response:** ```json { "auth_url": "https://kauth.kakao.com/oauth/authorize?client_id=...&redirect_uri=...&response_type=code" } ``` ### 4.2 카카오 콜백 (로그인/가입 처리) ``` POST /user/auth/kakao/callback ``` **Request:** ```json { "code": "인가코드" } ``` **Response (성공):** ```json { "access_token": "eyJhbGciOiJIUzI1NiIs...", "refresh_token": "eyJhbGciOiJIUzI1NiIs...", "token_type": "Bearer", "expires_in": 3600, "user": { "id": 1, "nickname": "홍길동", "email": "user@kakao.com", "profile_image_url": "https://...", "is_new_user": false } } ``` ### 4.3 토큰 갱신 ``` POST /user/auth/refresh ``` **Request:** ```json { "refresh_token": "eyJhbGciOiJIUzI1NiIs..." } ``` **Response:** ```json { "access_token": "eyJhbGciOiJIUzI1NiIs...", "token_type": "Bearer", "expires_in": 3600 } ``` ### 4.4 로그아웃 ``` POST /user/auth/logout Authorization: Bearer {access_token} ``` ### 4.5 모든 기기에서 로그아웃 ``` POST /user/auth/logout/all Authorization: Bearer {access_token} ``` ### 4.6 내 정보 조회 ``` GET /user/auth/me Authorization: Bearer {access_token} ``` **Response:** ```json { "id": 1, "kakao_id": 1234567890, "nickname": "홍길동", "email": "user@kakao.com", "profile_image_url": "https://...", "is_admin": false, "created_at": "2026-01-14T16:00:00" } ``` --- ## 5. 환경 설정 ### 5.1 카카오 개발자 설정 1. [카카오 개발자 콘솔](https://developers.kakao.com) 접속 2. 애플리케이션 생성 3. 플랫폼 > Web 사이트 도메인 등록 4. 카카오 로그인 > Redirect URI 등록 5. 동의항목 > 필요한 정보 설정 ### 5.2 .env 설정 ```env # 카카오 OAuth KAKAO_CLIENT_ID=your_rest_api_key KAKAO_CLIENT_SECRET=your_client_secret # 선택 KAKAO_REDIRECT_URI=https://your-domain.com/api/v1/auth/kakao/callback # JWT JWT_SECRET=your-super-secret-key-min-32-characters JWT_ALGORITHM=HS256 JWT_ACCESS_TOKEN_EXPIRE_MINUTES=60 JWT_REFRESH_TOKEN_EXPIRE_DAYS=7 ``` ### 5.3 config.py 설정 ```python class KakaoSettings(BaseSettings): KAKAO_CLIENT_ID: str = Field(...) KAKAO_CLIENT_SECRET: str = Field(default="") KAKAO_REDIRECT_URI: str = Field(...) model_config = _base_config class JWTSettings(BaseSettings): JWT_SECRET: str = Field(...) JWT_ALGORITHM: str = Field(default="HS256") JWT_ACCESS_TOKEN_EXPIRE_MINUTES: int = Field(default=60) JWT_REFRESH_TOKEN_EXPIRE_DAYS: int = Field(default=7) model_config = _base_config ``` --- ## 6. 에러 처리 ### 6.1 에러 코드 정의 | HTTP Status | Error Code | 설명 | |-------------|------------|------| | 400 | `INVALID_CODE` | 유효하지 않은 인가 코드 | | 400 | `KAKAO_AUTH_FAILED` | 카카오 인증 실패 | | 401 | `TOKEN_EXPIRED` | 토큰 만료 | | 401 | `INVALID_TOKEN` | 유효하지 않은 토큰 | | 401 | `TOKEN_REVOKED` | 취소된 토큰 | | 403 | `USER_INACTIVE` | 비활성화된 계정 | | 403 | `ADMIN_REQUIRED` | 관리자 권한 필요 | | 404 | `USER_NOT_FOUND` | 사용자 없음 | | 500 | `KAKAO_API_ERROR` | 카카오 API 오류 | ### 6.2 에러 응답 형식 ```json { "detail": { "code": "TOKEN_EXPIRED", "message": "토큰이 만료되었습니다. 다시 로그인해주세요." } } ``` --- ## 부록: 파일 구조 ``` app/user/ ├── __init__.py ├── models.py # User, RefreshToken 모델 ├── exceptions.py # 사용자 정의 예외 ├── schemas/ │ ├── __init__.py │ └── user_schema.py # Pydantic 스키마 ├── services/ │ ├── __init__.py │ ├── auth.py # 인증 서비스 │ ├── jwt.py # JWT 유틸리티 │ └── kakao.py # 카카오 OAuth 클라이언트 ├── dependencies/ │ ├── __init__.py │ └── auth.py # 인증 의존성 (get_current_user 등) └── api/ └── routers/ └── v1/ ├── __init__.py └── auth.py # 인증 API 라우터 ```