11 KiB
11 KiB
카카오 소셜 로그인 구현 가이드
목차
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 응답 매핑
// 카카오 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:
{
"auth_url": "https://kauth.kakao.com/oauth/authorize?client_id=...&redirect_uri=...&response_type=code"
}
4.2 카카오 콜백 (로그인/가입 처리)
POST /user/auth/kakao/callback
Request:
{
"code": "인가코드"
}
Response (성공):
{
"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:
{
"refresh_token": "eyJhbGciOiJIUzI1NiIs..."
}
Response:
{
"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:
{
"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 카카오 개발자 설정
- 카카오 개발자 콘솔 접속
- 애플리케이션 생성
- 플랫폼 > Web 사이트 도메인 등록
- 카카오 로그인 > Redirect URI 등록
- 동의항목 > 필요한 정보 설정
5.2 .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 설정
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 에러 응답 형식
{
"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 라우터