diff --git a/troubleshooting/250917_naverworks_oauth_implementation.md b/troubleshooting/250917_naverworks_oauth_implementation.md deleted file mode 100644 index 35dfd1b..0000000 --- a/troubleshooting/250917_naverworks_oauth_implementation.md +++ /dev/null @@ -1,335 +0,0 @@ -# NAVER WORKS OAuth 2.0 구현 가이드 - -**작성일**: 2025-09-17 -**작성자**: happybell80 -**상태**: 구현 대기 - -## 1. 현재 상태 분석 - -### 1.1 기존 Slack OAuth 구현 확인 -**파일 위치**: `auth-server/app/providers/slack.py` - -#### Slack OAuth 엔드포인트 구조 -```python -# OIDC 사용자 로그인 -GET /auth/slack/login/ → slack_login() -GET|POST /auth/slack/login/callback → slack_login_callback() - -# Bot 설치 (Passport) -GET /auth/slack/passport/install → slack_install() -GET /auth/slack/passport/callback → slack_callback() -GET /auth/slack/passport/status/{workspace_id} → slack_status() -DELETE /auth/slack/passport/uninstall/{workspace_id} → slack_uninstall() -``` - -#### Slack OAuth URL -- **OIDC Authorize**: `https://slack.com/openid/connect/authorize` -- **OIDC Token**: `https://slack.com/api/openid.connect.token` -- **OIDC Userinfo**: `https://slack.com/api/openid.connect.userInfo` -- **Bot Authorize**: `https://slack.com/oauth/v2/authorize` -- **Bot Token**: `https://slack.com/api/oauth.v2.access` - -#### Slack 구현 패턴 -1. State 생성 → Redis 저장 (TTL 300s) -2. OAuth 리다이렉트 -3. Callback에서 state 검증 -4. Code → Token 교환 -5. Userinfo 조회 -6. DB User 매핑 (oauth_provider="slack", oauth_id=sub) -7. JWT 생성 → Redis temp code 저장 -8. Frontend로 리다이렉트 - -### 1.2 NAVER WORKS 현재 설정 -**문서**: `DOCS/ideas/250916_네이버웍스_캘린더_API_연동_가이드.md` - -- **앱 이름**: Ro-being -- **소속**: company-x.partners (155032) -- **Redirect URL (콘솔 설정)**: `https://auth.robeing.com/oauth/naverworks/callback` -- **활성 Scopes**: openid, profile, email, calendar, contact, file, mail, task, user -- **Token 설정**: Access Token 1시간, Refresh Token Rotation On - -## 2. NAVER WORKS OAuth 2.0 구현 명세 - -### 2.1 공식 OAuth 엔드포인트 -**확인된 LINE WORKS API 2.0 엔드포인트**: -- **Authorization**: `https://auth.worksmobile.com/oauth2/v2.0/authorize` -- **Token**: `https://auth.worksmobile.com/oauth2/v2.0/token` -- **Userinfo**: `https://www.worksapis.com/v1.0/oidc/userinfo` -- **API Base**: `https://www.worksapis.com/v1.0/` - -### 2.2 구현 필요 파일 - -#### 신규 생성 -1. **`auth-server/app/providers/naverworks.py`** -```python -from fastapi import APIRouter, Request, HTTPException, Depends -from fastapi.responses import RedirectResponse -import httpx -import jwt -import json -import uuid -from datetime import datetime, timedelta -from app.core.auth import create_access_token -from app.models.user import User -from app.core.config import settings -from app.db.redis_client import redis_client - -router = APIRouter() - -NAVERWORKS_AUTH_URL = "https://auth.worksmobile.com/oauth2/v2.0/authorize" -NAVERWORKS_TOKEN_URL = "https://auth.worksmobile.com/oauth2/v2.0/token" -NAVERWORKS_USERINFO_URL = "https://www.worksapis.com/v1.0/oidc/userinfo" -NAVERWORKS_API_BASE = "https://www.worksapis.com/v1.0" - -@router.get("/login/") -async def naverworks_login(request: Request, redirect_uri: str = None): - """NAVER WORKS OAuth 로그인 시작""" - # 구현 내용... - -@router.get("/callback") -@router.post("/callback") # form_post 지원 -async def naverworks_login_callback(request: Request): - """NAVER WORKS OAuth 콜백 처리""" - # 구현 내용... - -# Service Account JWT 인증 헬퍼 -async def get_service_account_token(): - """서비스 계정으로 Access Token 발급""" - # JWT assertion 생성 - # Token endpoint 호출 - # 구현 내용... -``` - -#### 기존 파일 수정 -2. **`auth-server/app/main.py`** -```python -# 추가 -from app.providers import naverworks - -# 라우터 등록 -app.include_router( - naverworks.router, - prefix="/auth/naverworks", - tags=["auth-naverworks"] -) -``` - -3. **`auth-server/.env`** -```bash -# NAVER WORKS OAuth -NAVERWORKS_CLIENT_ID=[Client ID from console] -NAVERWORKS_CLIENT_SECRET=[Client Secret from console] -NAVERWORKS_REDIRECT_URI=https://auth.ro-being.com/auth/naverworks/callback -NAVERWORKS_SERVICE_ACCOUNT=[Service Account from console] -NAVERWORKS_PRIVATE_KEY_PATH=/secure/naverworks/private_key.json -``` - -### 2.3 데이터베이스 스키마 - -#### 신규 테이블 (선택적) -```sql --- NAVER WORKS 전용 매핑 테이블 (필요시) -CREATE TABLE naverworks_user_mapping ( - naverworks_user_id VARCHAR(100) NOT NULL, - naverworks_org_id VARCHAR(100) NOT NULL, - user_id UUID NOT NULL REFERENCES users(id), - created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, - PRIMARY KEY (naverworks_user_id, naverworks_org_id) -); - --- NAVER WORKS 토큰 저장 (Service Account용) -CREATE TABLE naverworks_tokens ( - id UUID PRIMARY KEY DEFAULT gen_random_uuid(), - org_id VARCHAR(100) NOT NULL, - access_token TEXT NOT NULL, - refresh_token TEXT, - expires_at TIMESTAMP NOT NULL, - created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, - updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP -); -``` - -#### 기존 users 테이블 활용 -- `oauth_provider`: "naverworks" -- `oauth_id`: NAVER WORKS userId 또는 sub claim -- `email`: 사용자 이메일 -- `name`: 사용자 이름 - -### 2.4 구현 플로우 - -#### 사용자 로그인 (OAuth 2.0 + OIDC) -``` -1. GET /auth/naverworks/login/?redirect_uri={frontend_url} - - State 생성 (UUID) - - Redis 저장: oauth:state:{state} = {"redirect_uri", "created_at"} - - Redirect to: https://auth.worksmobile.com/oauth2/v2.0/authorize - ?client_id={NAVERWORKS_CLIENT_ID} - &redirect_uri={NAVERWORKS_REDIRECT_URI} - &scope=openid+profile+email - &response_type=code - &state={state} - -2. GET|POST /auth/naverworks/callback?code={code}&state={state} - - State 검증 (Redis 조회 및 삭제) - - Token 교환: - POST https://auth.worksmobile.com/oauth2/v2.0/token - { - "code": code, - "client_id": NAVERWORKS_CLIENT_ID, - "client_secret": NAVERWORKS_CLIENT_SECRET, - "redirect_uri": NAVERWORKS_REDIRECT_URI, - "grant_type": "authorization_code" - } - - Userinfo 조회: - GET https://www.worksapis.com/v1.0/oidc/userinfo - Headers: Authorization: Bearer {access_token} - - User 조회/생성: - - oauth_provider="naverworks" - - oauth_id={sub 또는 userId} - - JWT 생성 - - 임시 코드 생성 → Redis: auth:temp:{temp_code} - - Redirect: {redirect_uri}?code={temp_code} - -3. Frontend: POST /auth/verify - - 임시 코드로 JWT 토큰 수령 -``` - -#### Service Account 인증 (JWT) -``` -1. Private Key 로드 (파일 시스템) -2. JWT Assertion 생성: - - iss: NAVERWORKS_CLIENT_ID - - sub: NAVERWORKS_SERVICE_ACCOUNT - - iat: 현재 시간 - - exp: 현재 시간 + 1시간 -3. Token 요청: - POST https://auth.worksmobile.com/oauth2/v2.0/token - { - "assertion": jwt_assertion, - "grant_type": "urn:ietf:params:oauth:grant-type:jwt-bearer", - "client_id": NAVERWORKS_CLIENT_ID, - "client_secret": NAVERWORKS_CLIENT_SECRET, - "scope": "calendar contact mail user" - } -4. Access Token 캐싱 (Redis, TTL 3600s) -``` - -### 2.5 API 사용 예시 - -#### 캘린더 일정 생성 -```python -async def create_calendar_event(user_id: str, event_data: dict): - token = await get_service_account_token() - - async with httpx.AsyncClient() as client: - response = await client.post( - f"{NAVERWORKS_API_BASE}/users/{user_id}/calendar/events", - headers={"Authorization": f"Bearer {token}"}, - json=event_data - ) - return response.json() -``` - -## 3. 구현 체크리스트 - -### 필수 작업 -- [ ] `auth-server/app/providers/naverworks.py` 생성 -- [ ] `auth-server/app/main.py`에 라우터 등록 -- [ ] `.env` 파일에 환경변수 추가 -- [ ] Redis key 패턴 구현 (oauth:state:*, auth:temp:*) -- [ ] User 모델 매핑 로직 -- [ ] JWT 토큰 생성 및 검증 - -### 선택 작업 -- [ ] NAVER WORKS 전용 테이블 생성 (필요시) -- [ ] Service Account JWT 인증 구현 -- [ ] Refresh Token 처리 로직 -- [ ] 에러 핸들링 및 재시도 로직 - -### Frontend 연동 -- [ ] 로그인 버튼 추가 -- [ ] `/auth/naverworks/login` 리다이렉트 -- [ ] 콜백 처리 및 토큰 저장 - -## 4. 보안 고려사항 - -### 비밀 키 관리 -- **Private Key 처리 완료** (2025-09-17): - - Git에 임시 commit 후 서버 전송 완료 - - 서버 51123에 안전하게 저장 - - Git에서 즉시 삭제 (commit a4a2b9c) - - 서버 경로: `/secure/naverworks/private_20250917185550.key` -- Client Secret은 환경변수로만 관리 -- Private Key 파일 권한 600 설정 필수 -- **확인필요**: 한 번에 하나의 Private Key만 활성화 (콘솔 제약) - -### 도메인 일치 -- **결정 완료**: `auth.ro-being.com` 사용 - - 콘솔 설정 변경 필요: auth.robeing.com → auth.ro-being.com - - 기존 Slack과 통일 - -### 토큰 보안 -- Access Token은 Redis에 임시 저장 (TTL 설정) -- Refresh Token은 암호화하여 DB 저장 -- Service Account 토큰은 게이트웨이 서버에서만 사용 - -## 5. 테스트 시나리오 - -### 로그인 플로우 테스트 -1. `/auth/naverworks/login` 접속 -2. NAVER WORKS 로그인 페이지 확인 -3. 인증 후 콜백 처리 확인 -4. JWT 토큰 발급 확인 -5. Frontend 리다이렉트 확인 - -### API 호출 테스트 -1. Service Account 토큰 발급 -2. 캘린더 API 호출 테스트 -3. 사용자 정보 조회 테스트 -4. 에러 처리 확인 - -## 6. 참고 자료 - -### 내부 문서 -- Slack OAuth 구현: `auth-server/app/providers/slack.py` -- Gmail OAuth 구현: `auth-server/app/providers/gmail_passport.py` -- NAVER WORKS 설정: `DOCS/ideas/250916_네이버웍스_캘린더_API_연동_가이드.md` - -### 외부 문서 -- [LINE WORKS Developers](https://developers.worksmobile.com) -- [OAuth 2.0 인증 가이드](https://developers.worksmobile.com/kr/docs/auth-oauth) -- [API Reference](https://developers.worksmobile.com/kr/reference/introduction) - -## 7. 구현 우선순위 - -1. **Phase 1** (즉시) - - 환경변수 설정 - - 기본 OAuth 로그인 플로우 - - User 매핑 로직 - -2. **Phase 2** (1주 내) - - Service Account 인증 - - 캘린더 API 연동 - - 에러 핸들링 - -3. **Phase 3** (2주 내) - - Refresh Token 자동 갱신 - - 전체 API 통합 - - 모니터링 및 로깅 - -## 8. 미결 사항 - -### 결정 완료 -- [x] Redirect URL 도메인: `auth.ro-being.com` 사용 -- [x] Private Key: 서버 51123 `/secure/naverworks/` 저장 -- [x] 테이블: `naverworks_token` (team 스키마, 단수형) - -### 확인 필요 -- [ ] NAVER WORKS OIDC userinfo endpoint 정확한 응답 형식 -- [ ] Service Account JWT 서명 알고리즘 -- [ ] Rate Limit 및 쿼터 제한 -- [ ] Private Key 교체 시 기존 토큰 유효성 - ---- -*작성: 2025-09-17 / happybell80* -*다음 업데이트: 구현 완료 후* \ No newline at end of file