From fc436e2ce7316af69f00ef58845749384ba27d68 Mon Sep 17 00:00:00 2001 From: happybell80 Date: Wed, 17 Sep 2025 22:51:27 +0900 Subject: [PATCH] docs: Update NAVER WORKS OAuth integration guide MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Move guide to troubleshooting with today's date - Update implementation status and verification - Add email-based user integration details - Fix file paths and configuration details ๐Ÿค– Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- ...ฒ„์›์Šค_์บ˜๋ฆฐ๋”_API_์—ฐ๋™_๊ฐ€์ด๋“œ.md | 255 ++++++++++++++++++ 1 file changed, 255 insertions(+) create mode 100644 troubleshooting/250917_๋„ค์ด๋ฒ„์›์Šค_์บ˜๋ฆฐ๋”_API_์—ฐ๋™_๊ฐ€์ด๋“œ.md diff --git a/troubleshooting/250917_๋„ค์ด๋ฒ„์›์Šค_์บ˜๋ฆฐ๋”_API_์—ฐ๋™_๊ฐ€์ด๋“œ.md b/troubleshooting/250917_๋„ค์ด๋ฒ„์›์Šค_์บ˜๋ฆฐ๋”_API_์—ฐ๋™_๊ฐ€์ด๋“œ.md new file mode 100644 index 0000000..dd9ffb3 --- /dev/null +++ b/troubleshooting/250917_๋„ค์ด๋ฒ„์›์Šค_์บ˜๋ฆฐ๋”_API_์—ฐ๋™_๊ฐ€์ด๋“œ.md @@ -0,0 +1,255 @@ +# ๋„ค์ด๋ฒ„์›์Šค API ์—ฐ๋™ ๊ฐ€์ด๋“œ + +**[ํ˜„์žฌ ํ”„๋กœ์ ํŠธ ์ƒํƒœ]** ๋„ค์ด๋ฒ„์›์Šค API ์—ฐ๋™ ๋ฏธ๊ตฌํ˜„ (OAuth2 ํ† ํฐ ๊ด€๋ฆฌ ๋กœ์ง ์—†์Œ, ๊ด€๋ จ skill ์„œ๋น„์Šค ๋ฏธ์กด์žฌ, auth-server์— Works API ์ธ์ฆ ๋ฏธํƒ‘์žฌ). + +## ๊ตฌํ˜„ ํ˜„ํ™ฉ ๋ฐ ํ•„์š” ์ž‘์—… + +### ํ˜„์žฌ ์ƒํƒœ +- **auth-server**: โœ… Phase 1 ๋กœ๊ทธ์ธ ๊ตฌํ˜„ ์™„๋ฃŒ (2025-09-17) + - `/auth/naverworks/login` ์ž‘๋™ + - `/auth/naverworks/callback` ์ž‘๋™ + - `/auth/naverworks/status` ์ž‘๋™ +- **skill ์„œ๋น„์Šค**: NAVER WORKS ์ „์šฉ ์Šคํ‚ฌ ์—†์Œ (Phase 2) +- **nginx**: NAVER WORKS ๋ผ์šฐํŒ… ์„ค์ • ์—†์Œ +- **.env ์„ค์ •**: โœ… ์™„๋ฃŒ (NAVER_WORKS_* ๋ณ€์ˆ˜) +- **Frontend**: โŒ ๋ฏธ๊ตฌํ˜„ (๋กœ๊ทธ์ธ ๋ฒ„ํŠผ, Auth Context ์ˆ˜์ • ํ•„์š”) + +### ํ™•์ธ๋œ OAuth ์—”๋“œํฌ์ธํŠธ ํŒจํ„ด + +#### ๐Ÿ“ Google (Gmail) OAuth - ๊ตฌํ˜„๋จ +**API ์—”๋“œํฌ์ธํŠธ**: +- `/auth/gmail/login` - ๋กœ๊ทธ์ธ ์‹œ์ž‘ +- `/auth/gmail/callback` - OAuth ์ฝœ๋ฐฑ +- `/auth/gmail/passport/` - Passport ๋กœ๊ทธ์ธ ์‹œ์ž‘ +- `/auth/gmail/passport/callback` - Passport ์ฝœ๋ฐฑ +- `/auth/gmail/passport/status` - Passport ์ƒํƒœ ํ™•์ธ + +#### ๐Ÿ“ Slack OAuth - ๊ตฌํ˜„๋จ +**API ์—”๋“œํฌ์ธํŠธ**: +- `/auth/slack/login/` - ๋กœ๊ทธ์ธ ์‹œ์ž‘ +- `/auth/slack/login/callback` - OAuth ์ฝœ๋ฐฑ +- `/auth/slack/passport/install` - Passport ์„ค์น˜ +- `/auth/slack/passport/callback` - Passport ์ฝœ๋ฐฑ +- `/auth/slack/passport/status/{workspace_id}` - Passport ์ƒํƒœ + +#### ๐Ÿ“ NAVER WORKS OAuth - ๊ตฌํ˜„ ์˜ˆ์ • +**API ์—”๋“œํฌ์ธํŠธ** (Gmail/Slack ํŒจํ„ด ์ฐธ์กฐ): +- `/auth/naverworks/login` - ๋กœ๊ทธ์ธ ์‹œ์ž‘ +- `/auth/naverworks/callback` - OAuth ์ฝœ๋ฐฑ +- `/auth/naverworks/passport/install` - Passport ์„ค์น˜/๊ถŒํ•œ ๋ถ€์—ฌ (์„ ํƒ์ ) +- `/auth/naverworks/passport/callback` - Passport ์ฝœ๋ฐฑ (์„ ํƒ์ ) + +**์™ธ๋ถ€ OAuth URL**: +- **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) ์•ฑ ์„ค์ • ํ˜„ํ™ฉ + +- **์•ฑ ์ด๋ฆ„**: Ro-being +- **์†Œ์†**: company-x.partners (155032) + +### 1.1. ์ธ์ฆ ์ •๋ณด + +- **Client ID**: `[ํ™˜๊ฒฝ๋ณ€์ˆ˜ NAVERWORKS_CLIENT_ID ์ฐธ์กฐ]` +- **Client Secret**: `[ํ™˜๊ฒฝ๋ณ€์ˆ˜ NAVERWORKS_CLIENT_SECRET ์ฐธ์กฐ]` + - > **โš ๏ธ ๊ฒฝ๊ณ : ์ด ๊ฐ’์€ ์™ธ๋ถ€์— ๋…ธ์ถœ๋˜์–ด์„œ๋Š” ์•ˆ ๋˜๋ฉฐ, Git ๋“ฑ ๋ฒ„์ „ ๊ด€๋ฆฌ ์‹œ์Šคํ…œ์— ํฌํ•จํ•˜์ง€ ๋งˆ์‹ญ์‹œ์˜ค. Vault ๋˜๋Š” ์•”ํ˜ธํ™”๋œ ํ™˜๊ฒฝ ๋ณ€์ˆ˜๋ฅผ ํ†ตํ•ด ์•ˆ์ „ํ•˜๊ฒŒ ๊ด€๋ฆฌํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.** +- **Service Account**: `[ํ™˜๊ฒฝ๋ณ€์ˆ˜ NAVERWORKS_SERVICE_ACCOUNT ์ฐธ์กฐ]` + +### 1.2. ํ† ํฐ ์„ค์ • + +- **Access Token ์œ ํšจ๊ธฐ๊ฐ„**: 1์‹œ๊ฐ„ +- **Refresh Token Rotation**: On (๋ณด์•ˆ ๊ฐ•ํ™”) + +### 1.3. OAuth ์„ค์ • + +- **๊ตฌ์„ฑ์› ๊ณ„์ • ์ธ์ฆ Redirect URL** (์ฝ˜์†” ์„ค์ •): + - `https://auth.ro-being.com/auth/naverworks/callback` (์ผ๋ฐ˜ ๋กœ๊ทธ์ธ) + - `https://auth.ro-being.com/auth/naverworks/passport/callback` (Passport ๋กœ๊ทธ์ธ) +- **OIDC Logout Redirection**: + - `https://example.com` (๊ธฐ๋ณธ๊ฐ’ ์œ ์ง€) +- **ํ™œ์„ฑํ™”๋œ Scopes**: + - `openid`, `profile`, `email` (OIDC ์‚ฌ์šฉ์ž ์‹๋ณ„์šฉ) + - `calendar` (์บ˜๋ฆฐ๋” ์ฝ๊ธฐ/์“ฐ๊ธฐ) + - `contact` (์ฃผ์†Œ๋ก ์ฝ๊ธฐ/์“ฐ๊ธฐ) + - `file` (๋“œ๋ผ์ด๋ธŒ ํŒŒ์ผ ์ ‘๊ทผ) + - `mail` (๋ฉ”์ผ ์ฝ๊ธฐ/๋ณด๋‚ด๊ธฐ) + - `task` (์—…๋ฌด ๊ด€๋ฆฌ) + - `user` (์กฐ์ง ๋‚ด ์‚ฌ์šฉ์ž ์ •๋ณด ์กฐํšŒ) + +--- + +## 2. ์ธ์ฆ ๋ฐฉ์‹ + +๋„ค์ด๋ฒ„์›์Šค API๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ๋จผ์ € **Access Token**์„ ๋ฐœ๊ธ‰๋ฐ›์•„์•ผ ํ•ฉ๋‹ˆ๋‹ค. ํ˜„์žฌ ์•ฑ ์„ค์ •์— ๋”ฐ๋ผ ์•„๋ž˜ ๋‘ ๊ฐ€์ง€ ๋ฐฉ์‹ ๋ชจ๋‘ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค. + +1. **๊ตฌ์„ฑ์› ๊ณ„์ •์œผ๋กœ ์ธ์ฆ (OAuth 2.0 / OIDC)**: ์‚ฌ์šฉ์ž๊ฐ€ ์ง์ ‘ ๋กœ๊ทธ์ธํ•˜์—ฌ ์ž์‹ ์˜ ๋ฐ์ดํ„ฐ์— ๋Œ€ํ•œ ์ ‘๊ทผ์„ ํ—ˆ์šฉํ•˜๋Š” ๋ฐฉ์‹์ž…๋‹ˆ๋‹ค. (์˜ˆ: "๋‚ด ์บ˜๋ฆฐ๋” ์ผ์ • ์กฐํšŒ") +2. **์„œ๋น„์Šค ๊ณ„์ •์œผ๋กœ ์ธ์ฆ (JWT)**: ์‚ฌ์šฉ์ž ๋กœ๊ทธ์ธ ์—†์ด, ์‹œ์Šคํ…œ(๋กœ๋น™)์ด ์กฐ์ง ์ „์ฒด์˜ ๋ฐ์ดํ„ฐ์— ์ ‘๊ทผํ•  ๋•Œ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. (์˜ˆ: ์ฃผ๊ธฐ์ ์ธ ๋ฐ์ดํ„ฐ ๋™๊ธฐํ™”) + +## 3. API ์‚ฌ์šฉ ์˜ˆ์‹œ ๋ฐ ์ฃผ์š” ์—”๋“œํฌ์ธํŠธ + +### 3.1. ์บ˜๋ฆฐ๋” (Calendar API) + +- **์Šค์ฝ”ํ”„**: `calendar` +- **์ฃผ์š” ์—”๋“œํฌ์ธํŠธ**: + - `GET /v1.0/users/{userId}/calendar/events`: ํŠน์ • ์‚ฌ์šฉ์ž์˜ ์ผ์ • ๋ชฉ๋ก ์กฐํšŒ + - `POST /v1.0/users/{userId}/calendar/events`: ์ƒˆ ์ผ์ • ์ƒ์„ฑ + - `PUT /v1.0/users/{userId}/calendar/events/{eventId}`: ๊ธฐ์กด ์ผ์ • ์ˆ˜์ • + +- **์š”์ฒญ ์˜ˆ์‹œ: ์ƒˆ ์ผ์ • ์ƒ์„ฑ** + `POST https://www.worksapis.com/v1.0/users/{userId}/calendar/events` + ```json + { + "subject": "Team Meeting", + "start": { + "date": "2025-09-18", + "time": "10:00:00" + }, + "end": { + "date": "2025-09-18", + "time": "11:00:00" + }, + "attendees": [ + { + "email": "member1@example.com", + "isOptional": false + } + ] + } + ``` + +### 3.2. ์ฃผ์†Œ๋ก (Contact API) + +- **์Šค์ฝ”ํ”„**: `contact`, `user` +- **์ฃผ์š” ์—”๋“œํฌ์ธํŠธ**: + - `GET /v1.0/contacts`: ๊ณ ๊ฐ/๊ฑฐ๋ž˜์ฒ˜ ์—ฐ๋ฝ์ฒ˜ ๋ชฉ๋ก ์กฐํšŒ + - `POST /v1.0/contacts`: ์ƒˆ ์—ฐ๋ฝ์ฒ˜ ์ƒ์„ฑ + - `GET /v1.0/users/{userId}`: ์กฐ์ง ๋‚ด ์‚ฌ์šฉ์ž ์ •๋ณด ์กฐํšŒ + +### 3.3. ๋ฉ”์ผ (Mail API) + +- **์Šค์ฝ”ํ”„**: `mail` +- **์ฃผ์š” ์—”๋“œํฌ์ธํŠธ**: + - `POST /v1.0/users/{userId}/mail`: ๋ฉ”์ผ ๋ฐœ์†ก + - `GET /v1.0/users/{userId}/mail/messages/{messageId}`: ํŠน์ • ๋ฉ”์ผ ์ƒ์„ธ ์กฐํšŒ + +## 4. ๋กœ๋น™ ์—ฐ๋™ ์•„ํ‚คํ…์ฒ˜ + +### 4.1. ์‹œํฌ๋ฆฟ ๊ด€๋ฆฌ (์˜จํ”„๋ ˆ๋ฏธ์Šค 2์„œ๋ฒ„ ํ™˜๊ฒฝ) + +- **์›์น™**: ์˜๊ตฌ ์‹œํฌ๋ฆฟ(Client Secret, Private Key)์€ **๊ฒŒ์ดํŠธ์›จ์ด ์„œ๋ฒ„**์—๋งŒ ์ค‘์•™ ์ง‘์ค‘์‹์œผ๋กœ ๋ณด๊ด€ํ•ฉ๋‹ˆ๋‹ค. +- **๊ตฌํ˜„**: ๊ฒŒ์ดํŠธ์›จ์ด ์„œ๋ฒ„์—์„œ HashiCorp Vault ๋˜๋Š” ์•”ํ˜ธํ™”๋œ ํŒŒ์ผ ์‹œ์Šคํ…œ(`600` ๊ถŒํ•œ)์„ ์‚ฌ์šฉํ•˜์—ฌ Client ID/Secret์„ ๊ด€๋ฆฌํ•˜๊ณ , ์ปจํ…Œ์ด๋„ˆ์—๋Š” ์ฝ๊ธฐ ์ „์šฉ(`:ro`)์œผ๋กœ ๋งˆ์šดํŠธํ•ฉ๋‹ˆ๋‹ค. +- **๋กœ๋น™/์Šคํ‚ฌ ์„œ๋ฒ„**: ๊ฒŒ์ดํŠธ์›จ์ด๋ฅผ ํ†ตํ•ด ๋ฐœ๊ธ‰๋œ ๋‹จ๊ธฐ Access Token๋งŒ ๋ฐ›์•„ ์‚ฌ์šฉํ•˜๋ฉฐ, ์˜๊ตฌ ์‹œํฌ๋ฆฟ์„ ๋ณด๊ด€ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. + +### 4.2. ์ธ์ฆ ํ๋ฆ„ ๋ฐ ํ† ํฐ ๊ด€๋ฆฌ + +- **JWT ํ‚ค ๊ด€๋ฆฌ (JWKS)**: ๊ฒŒ์ดํŠธ์›จ์ด๋Š” JWT ์„œ๋ช…์— ์‚ฌ์šฉํ•˜๋Š” ๊ณต๊ฐœํ‚ค ๋ชฉ๋ก์„ `/.well-known/jwks.json` ์—”๋“œํฌ์ธํŠธ๋ฅผ ํ†ตํ•ด ๋…ธ์ถœํ•˜์—ฌ, ๋‹ค๋ฅธ ์„œ๋น„์Šค๋“ค์ด ํ† ํฐ์„ ์•ˆ์ „ํ•˜๊ฒŒ ๊ฒ€์ฆํ•˜๊ณ  ํ‚ค ๊ต์ฒด์— ๋Œ€์‘ํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•ฉ๋‹ˆ๋‹ค. +- **ํ† ํฐ ํ๋ฆ„**: ๋กœ๋น™/์Šคํ‚ฌ ์„œ๋ฒ„๋Š” ์™ธ๋ถ€ API๋ฅผ ์ง์ ‘ ํ˜ธ์ถœํ•˜๋Š” ๋Œ€์‹ , ๊ฒŒ์ดํŠธ์›จ์ด์— API ํ˜ธ์ถœ์„ ์œ„์ž„ํ•˜๊ณ  ํ•„์š”ํ•œ ๋‹จ๊ธฐ ํ† ํฐ์„ ๋ฐ›์•„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. + +## 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-infra`**: `/auth/naverworks`, `/api/naverworks` ๋ผ์šฐํŒ… ์„ค์ • + +#### DB ์Šคํ‚ค๋งˆ +- **Phase 1: ๋กœ๊ทธ์ธ ๊ตฌํ˜„** (ํ˜„์žฌ): + - ๊ธฐ์กด `user` ํ…Œ์ด๋ธ”๋งŒ ์‚ฌ์šฉ + - oauth_provider="naverworks" + - oauth_id={userinfo.sub} + - ์ด๋ฉ”์ผ ๊ธฐ๋ฐ˜ ์‚ฌ์šฉ์ž ํ†ตํ•ฉ: Gmail/Slack๊ณผ ๋™์ผ ์ด๋ฉ”์ผ์ด๋ฉด ๊ฐ™์€ User ๋ ˆ์ฝ”๋“œ ์‚ฌ์šฉ + +- **Phase 2: Passport ๊ตฌํ˜„** (๋‹ค์Œ): + - `team.naverworks_workspace`: Workspace ์ •๋ณด ์ €์žฅ + - `team.naverworks_token`: access_token/refresh_token ์ €์žฅ + - ๋ฉ”์ผ/์บ˜๋ฆฐ๋” API ์ ‘๊ทผ์šฉ + +### 5.2 ๊ตฌํ˜„ ํ”Œ๋กœ์šฐ (Slack ํŒจํ„ด ์ฐธ์กฐ) + +#### OAuth ๋กœ๊ทธ์ธ ์—”๋“œํฌ์ธํŠธ +- **GET /auth/naverworks/login/**: State ์ƒ์„ฑ โ†’ Redis ์ €์žฅ โ†’ OAuth ๋ฆฌ๋‹ค์ด๋ ‰ํŠธ +- **GET /auth/naverworks/callback**: State ๊ฒ€์ฆ โ†’ Token ๊ตํ™˜ โ†’ Userinfo ์กฐํšŒ โ†’ User ๋งคํ•‘ โ†’ JWT ๋ฐœ๊ธ‰ + - ์ฃผ์˜: ํ‘œ์ค€ OAuth 2.0์€ GET ์ฝœ๋ฐฑ ์‚ฌ์šฉ (Slack OIDC์˜ POST form_post์™€ ๋‹ค๋ฆ„) + +#### Redis Keys +- `oauth:state:{state}`: CSRF ๋ฐฉ์ง€์šฉ state ์ €์žฅ (TTL 300s) +- `auth:temp:{temp_code}`: Frontend ์ „๋‹ฌ์šฉ ์ž„์‹œ ์ฝ”๋“œ (TTL 60s) +- `naverworks:service:token`: Service Account ํ† ํฐ ์บ์‹ฑ (TTL 3600s) + +#### Slack OAuth ์ฐธ์กฐ ํŒŒ์ผ +- **๊ตฌํ˜„ ํŒจํ„ด**: `auth-server/app/providers/slack.py` +- **Gmail passport**: `auth-server/app/providers/gmail_passport.py` +- **JWT ์ƒ์„ฑ**: `auth-server/app/core/auth.py`์˜ create_access_token() + +### 5.3 ๊ฒฐ์ •/ํ™•์ธ ํ•„์š” ์‚ฌํ•ญ + +#### ๊ฒฐ์ •์‚ฌํ•ญ (ํ™•์ •) +- **Redirect URL ๋„๋ฉ”์ธ**: `auth.ro-being.com` ์‚ฌ์šฉ (Gmail/Slack๊ณผ ํ†ต์ผ) +- **Private Key ์ฒ˜๋ฆฌ**: + - 2025-09-17: Git ์ž„์‹œ commit ํ›„ ์„œ๋ฒ„ ์ „์†ก + - ์„œ๋ฒ„ ์ €์žฅ: Base64 ์ธ์ฝ”๋”ฉํ•˜์—ฌ .env์˜ NAVERWORKS_PRIVATE_KEY_BASE64์— ์ €์žฅ + - Git์—์„œ ์‚ญ์ œ ์™„๋ฃŒ (๋ณด์•ˆ์ƒ Git ์ €์žฅ ๊ธˆ์ง€) +- **NAVER WORKS ํ† ํฐ ํ…Œ์ด๋ธ”**: `naverworks_token` (team ์Šคํ‚ค๋งˆ ์•„๋ž˜, ๋‹จ์ˆ˜ํ˜•) + +#### ํ™•์ธ ์™„๋ฃŒ +- **OIDC userinfo ํ•„๋“œ**: `sub` (์‚ฌ์šฉ์ž ID), `email` (์ด๋ฉ”์ผ) +- **Service Account JWT ์„œ๋ช…**: RS256 ์•Œ๊ณ ๋ฆฌ์ฆ˜ (RSA 2048 bits) +- **์—๋Ÿฌ ์‘๋‹ต ํ˜•์‹**: JSON `{"error", "error_description", "error_uri"}` +- **response_mode**: ๊ธฐ๋ณธ query ์‚ฌ์šฉ (form_post ๋ถˆํ•„์š”) + +## 6. Frontend ์ˆ˜์ • ๊ณ„ํš (๋ฏธ๊ตฌํ˜„) + +### 6.1 ๋กœ๊ทธ์ธ ๋ฒ„ํŠผ ์ถ”๊ฐ€ โŒ +- **์œ„์น˜**: `frontend-customer/src/components/login-dialog.tsx` (์‹ค์ œ ํŒŒ์ผ๋ช…) +- **์•„์ด์ฝ˜**: `/assets/integrations/naverworks-icon.svg` (ํŒŒ์ผ ์กด์žฌ ํ™•์ธ๋จ) +- **๋™์ž‘**: `/auth/naverworks/login` ๋ฆฌ๋‹ค์ด๋ ‰ํŠธ +- **์ƒํƒœ**: ๋ฏธ๊ตฌํ˜„ + +### 6.2 Auth Context ์ˆ˜์ • โŒ +- **์œ„์น˜**: `frontend-customer/src/contexts/auth-context.tsx` +- **ํ•จ์ˆ˜ ์ถ”๊ฐ€**: `loginWithNaverWorks()` (context value์— ์ถ”๊ฐ€ ํ•„์š”) +- **AUTH_SERVER_URL**: `import.meta.env.VITE_AUTH_SERVER_URL || 'https://auth.ro-being.com'` ์‚ฌ์šฉ +- **ํŒจํ„ด**: Gmail/Slack๊ณผ ๋™์ผํ•œ OAuth ํ”Œ๋กœ์šฐ +- **redirect_uri ์ธ์ฝ”๋”ฉ**: `encodeURIComponent(window.location.origin)` ํ•„์ˆ˜ +- **์ƒํƒœ**: ๋ฏธ๊ตฌํ˜„ + +### 6.3 Skills Panel (Passport ์—ฐ๋™) โŒ +- **์œ„์น˜**: `frontend-customer/src/components/skills-items-panel.tsx` +- **sessionStorage key**: `naverworks_oauth_return_url` +- **์—”๋“œํฌ์ธํŠธ**: `/auth/naverworks/passport/install?user_id={userId}` +- **์ƒํƒœ**: Phase 2์—์„œ ๊ตฌํ˜„ ์˜ˆ์ • + +### 6.4 Callback ์ฒ˜๋ฆฌ โŒ +- URL hash (#auth=์ž„์‹œ์ฝ”๋“œ)์—์„œ ์ž„์‹œ ์ฝ”๋“œ ์ถ”์ถœ (๊ธฐ์กด ์ฝ”๋“œ ํŒจํ„ด) +- `/auth/verify` POST ํ˜ธ์ถœ๋กœ JWT ํš๋“ +- localStorage 'auth_token' ํ‚ค๋กœ ์ €์žฅ (์ฃผ์˜: ์ผ๋ถ€ ์„œ๋น„์Šค๋Š” 'token'๋„ ์ฒดํฌ) +- ์„ฑ๊ณต์‹œ URL ์ •๋ฆฌ: `window.history.replaceState()` ์‚ฌ์šฉ +- ์‹คํŒจ์‹œ ์—๋Ÿฌ ์ฒ˜๋ฆฌ: `window.location.hash = ''` ๋ฐ ๋กœ๊ทธ +- **์ƒํƒœ**: ๋ฏธ๊ตฌํ˜„ + +### 6.5 UI/UX โŒ +- ๋ฒ„ํŠผ ์Šคํƒ€์ผ: Google/Slack๊ณผ ๋™์ผํ•œ ๋””์ž์ธ ์‚ฌ์šฉ +- ๋ฒ„ํŠผ ํ…์ŠคํŠธ: "NAVER WORKS๋กœ ๊ณ„์†ํ•˜๊ธฐ" +- ์—ฐ๋™ ์ƒํƒœ ํ‘œ์‹œ ํ•„์š” +- **์ƒํƒœ**: ๋ฏธ๊ตฌํ˜„ + +## 7. ์ฐธ๊ณ  ์ž๋ฃŒ + +- **๋„ค์ด๋ฒ„์›์Šค ๊ฐœ๋ฐœ์ž ์„ผํ„ฐ (๊ณต์‹ ๋ฌธ์„œ):** [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) +- **๋‚ด๋ถ€ ์ฐธ์กฐ ์ฝ”๋“œ:** + - Slack OAuth: `auth-server/app/providers/slack.py` + - Gmail OAuth: `auth-server/app/providers/gmail_passport.py`