DOCS/troubleshooting/250917_naverworks_oauth_implementation.md
happybell80 d3f44cee2b 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
2025-09-17 20:22:27 +09:00

10 KiB

NAVER WORKS OAuth 2.0 구현 가이드

작성일: 2025-09-17 작성자: happybell80 상태: 구현 대기

1. 현재 상태 분석

1.1 기존 Slack OAuth 구현 확인

파일 위치: auth-server/app/providers/slack.py

Slack OAuth 엔드포인트 구조

# 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
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 호출
    # 구현 내용...

기존 파일 수정

  1. auth-server/app/main.py
# 추가
from app.providers import naverworks

# 라우터 등록
app.include_router(
    naverworks.router,
    prefix="/auth/naverworks",
    tags=["auth-naverworks"]
)
  1. auth-server/.env
# 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 데이터베이스 스키마

신규 테이블 (선택적)

-- 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 사용 예시

캘린더 일정 생성

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

외부 문서

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 다음 업데이트: 구현 완료 후