Update NAVER WORKS OAuth implementation documentation

- Add NAVER WORKS OAuth to authentication system architecture
- Update API integration guide with confirmed endpoints and decisions
- Create troubleshooting guide for implementation
This commit is contained in:
happybell80 2025-09-17 20:22:27 +09:00
parent 9ea40568a0
commit d3f44cee2b
3 changed files with 425 additions and 6 deletions

View File

@ -32,6 +32,15 @@
- GET/POST 콜백 모두 지원
- 하이브리드 사용자 매핑
#### NAVER WORKS OAuth
- **엔드포인트**: `/auth/naverworks/login`
- **콜백**: `/auth/naverworks/callback`
- **특징**:
- OAuth 2.0 + OpenID Connect
- Service Account (JWT) 지원
- Access Token 1시간, Refresh Token Rotation
- **결정필요**: Redirect URL 도메인 (auth.ro-being.com vs auth.robeing.com)
### 3. 데이터베이스 구조
#### users 테이블
@ -154,11 +163,18 @@ SLACK_CLIENT_ID=
SLACK_CLIENT_SECRET=
SLACK_REDIRECT_URI=
# Gmail OAuth
# Gmail OAuth
GMAIL_CLIENT_ID=
GMAIL_CLIENT_SECRET=
GMAIL_REDIRECT_URI=
# NAVER WORKS OAuth
NAVERWORKS_CLIENT_ID=
NAVERWORKS_CLIENT_SECRET=
NAVERWORKS_REDIRECT_URI=
NAVERWORKS_SERVICE_ACCOUNT=
NAVERWORKS_PRIVATE_KEY_PATH=
# Redis
REDIS_URL=redis://localhost:6379/0

View File

@ -2,6 +2,19 @@
**[현재 프로젝트 상태]** 네이버웍스 API 연동 미구현 (OAuth2 토큰 관리 로직 없음, 관련 skill 서비스 미존재, auth-server에 Works API 인증 미탑재).
## 구현 현황 및 필요 작업
### 현재 상태
- **auth-server**: NAVER WORKS OAuth 미구현 (Gmail, Slack만 존재)
- **skill 서비스**: NAVER WORKS 전용 스킬 없음
- **nginx**: NAVER WORKS 라우팅 설정 없음
### 확인된 NAVER WORKS OAuth 2.0 엔드포인트
- **Authorization**: `https://auth.worksmobile.com/oauth2/v2.0/authorize`
- **Token**: `https://auth.worksmobile.com/oauth2/v2.0/token`
- **Userinfo (OIDC)**: `https://www.worksapis.com/v1.0/oidc/userinfo`
- **API Base**: `https://www.worksapis.com/v1.0/`
---
## 1. 로빙(RO-BEING) 앱 설정 현황
@ -11,10 +24,10 @@
### 1.1. 인증 정보
- **Client ID**: `kFJu_ajl6tb8pBiPEEnS`
- **Client Secret**: `xIz5G0v4wn`
- **Client ID**: `[환경변수 NAVERWORKS_CLIENT_ID 참조]`
- **Client Secret**: `[환경변수 NAVERWORKS_CLIENT_SECRET 참조]`
- > **⚠️ 경고: 이 값은 외부에 노출되어서는 안 되며, Git 등 버전 관리 시스템에 포함하지 마십시오. Vault 또는 암호화된 환경 변수를 통해 안전하게 관리해야 합니다.**
- **Service Account**: `86rye.serviceaccount@company-x.partners`
- **Service Account**: `[환경변수 NAVERWORKS_SERVICE_ACCOUNT 참조]`
### 1.2. 토큰 설정
@ -102,11 +115,69 @@
- **JWT 키 관리 (JWKS)**: 게이트웨이는 JWT 서명에 사용하는 공개키 목록을 `/.well-known/jwks.json` 엔드포인트를 통해 노출하여, 다른 서비스들이 토큰을 안전하게 검증하고 키 교체에 대응할 수 있도록 합니다.
- **토큰 흐름**: 로빙/스킬 서버는 외부 API를 직접 호출하는 대신, 게이트웨이에 API 호출을 위임하고 필요한 단기 토큰을 받아 사용합니다.
## 5. 참고 자료
## 5. 구현 필요 사항
### 5.1 파일 생성/수정 목록
#### 생성 필요
- **`auth-server/app/providers/naverworks.py`**: OAuth 2.0 인증 플로우 구현
- **`skill-naverworks/`**: NAVER WORKS API 전용 스킬 서비스 (포트 8511)
#### 수정 필요
- **`auth-server/app/main.py`**: naverworks 라우터 등록 (`prefix="/auth/naverworks"`)
- **`auth-server/.env`**: NAVERWORKS_CLIENT_ID, SECRET, REDIRECT_URI 추가
- **`nginx-deploy`**: `/auth/naverworks`, `/api/naverworks` 라우팅 설정
### 5.2 구현 플로우 (Slack 패턴 참조)
#### OAuth 로그인 플로우
```python
# auth-server/app/providers/naverworks.py 구현 필요
@router.get("/login/")
async def naverworks_login():
# 1. State 생성 → Redis 저장 (TTL 300s)
# 2. Redirect to https://auth.worksmobile.com/oauth2/v2.0/authorize
@router.get("/callback")
@router.post("/callback") # form_post 지원
async def naverworks_login_callback():
# 1. State 검증
# 2. Code → Token 교환 (POST https://auth.worksmobile.com/oauth2/v2.0/token)
# 3. Userinfo 조회 (GET https://www.worksapis.com/v1.0/oidc/userinfo)
# 4. User DB 매핑 (oauth_provider="naverworks")
# 5. JWT 생성 → Redis temp code → Frontend redirect
```
#### Service Account JWT 인증
```python
async def get_service_account_token():
# 1. Private Key 로드 (파일 시스템)
# 2. JWT Assertion 생성
# 3. Token 요청 (grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer)
# 4. Access Token 캐싱 (Redis TTL 3600s)
```
### 5.3 결정/확인 필요 사항
#### 결정사항 (확정)
- **Redirect URL 도메인**: `auth.ro-being.com` 사용
- **Private Key 저장 경로**: `auth-server/private_20250917185550.key`
- **NAVER WORKS 토큰 테이블**: `naverworks_token` (team 스키마 아래, 단수형)
#### 확인필요
- **OIDC userinfo 응답 형식**: sub, userId 등 정확한 필드명
- **Service Account JWT 서명**: 알고리즘 (RS256 등)
- **Rate Limit**: API 호출 제한 및 쿼터
- **Private Key 교체 시**: 기존 토큰 유효성 유지 여부
## 6. 참고 자료
- **네이버웍스 개발자 센터 (공식 문서):** [developers.worksmobile.com](https://developers.worksmobile.com)
- [인증 가이드](https://developers.worksmobile.com/kr/docs/auth)
- [캘린더 API](https://developers.worksmobile.com/kr/document/10070?lang=ko)
- [주소록 API](https://developers.worksmobile.com/kr/docs/contact)
- [메일 API](https://developers.worksmobile.com/kr/docs/mail)
- **네이버 개발자 포럼:** API 관련 실제 질의응답을 참고할 수 있습니다.
- **내부 참조 코드:**
- Slack OAuth: `auth-server/app/providers/slack.py`
- Gmail OAuth: `auth-server/app/providers/gmail_passport.py`

View File

@ -0,0 +1,332 @@
# 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 저장 위치 (파일 시스템 vs Vault)
- Client Secret은 환경변수로만 관리
- Private Key 파일 권한 600 설정 필수
- **확인필요**: 한 번에 하나의 Private Key만 활성화 (콘솔 제약)
### 도메인 일치
- **결정필요**: Redirect URL 도메인 통일
- 콘솔 설정: `auth.robeing.com`
- 현재 Slack: `auth.ro-being.com`
- 하나로 통일 필요
### 토큰 보안
- 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. 미결 사항
### 결정 필요
- [ ] Redirect URL 도메인 (auth.ro-being.com vs auth.robeing.com)
- [ ] Private Key 저장 방식 (파일 vs Vault)
- [ ] NAVER WORKS 전용 테이블 생성 여부
### 확인 필요
- [ ] NAVER WORKS OIDC userinfo endpoint 정확한 응답 형식
- [ ] Service Account JWT 서명 알고리즘
- [ ] Rate Limit 및 쿼터 제한
- [ ] Private Key 교체 시 기존 토큰 유효성
---
*작성: 2025-09-17 / happybell80*
*다음 업데이트: 구현 완료 후*