From 1c8ef7fa30468ca1f5038cccb57737d306bd569f Mon Sep 17 00:00:00 2001 From: happybell80 Date: Mon, 1 Sep 2025 18:27:01 +0900 Subject: [PATCH] =?UTF-8?q?docs:=20Gmail=20OAuth=20404=20=EC=97=90?= =?UTF-8?q?=EB=9F=AC=20=ED=95=B4=EA=B2=B0=20=EB=B0=8F=20return=5Furl=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84=20=EB=AC=B8=EC=84=9C=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - email_sequences.md: Gmail Passport 방식 시퀀스 다이어그램 추가 - authentication_system.md: Gmail Passport 엔드포인트 문서화 - 트러블슈팅: 250901 Gmail OAuth 404 에러 및 return_url 구현 문서 추가 --- 300_architecture/380_authentication_system.md | 19 +++ 300_architecture/sequences/email_sequences.md | 30 ++-- ...pybell80_gmail_oauth_404_return_url_fix.md | 144 ++++++++++++++++++ 3 files changed, 180 insertions(+), 13 deletions(-) create mode 100644 troubleshooting/250901_happybell80_gmail_oauth_404_return_url_fix.md diff --git a/300_architecture/380_authentication_system.md b/300_architecture/380_authentication_system.md index cd077c3..e9e3d3d 100644 --- a/300_architecture/380_authentication_system.md +++ b/300_architecture/380_authentication_system.md @@ -112,6 +112,25 @@ sequenceDiagram - redirect_uri: "http://localhost:3000" - callback_url: "https://auth.ro-being.com/..." +## Gmail Passport 시스템 + +### 엔드포인트 +1. **발급 시작**: `GET /auth/gmail/passport` + - Parameters: + - `user_id`: 사용자 ID (필수) + - `return_url`: OAuth 완료 후 돌아갈 URL (선택) + - Response: Google OAuth 페이지로 302 Redirect + +2. **콜백 처리**: `GET /auth/gmail/passport/callback` + - Google OAuth 콜백 자동 처리 + - 토큰 저장 후 return_url 또는 /game으로 리다이렉트 + - 성공 시: `?gmail=success&email={email}` 파라미터 추가 + +### 특징 +- **원페이지 복귀**: OAuth 인증 후 원래 있던 페이지로 자동 복귀 +- **상태 관리**: state 파라미터에 return_url 포함하여 전달 +- **토큰 저장**: gmail_tokens 테이블에 암호화 저장 + ## 보안 고려사항 ### 구현된 보안 기능 diff --git a/300_architecture/sequences/email_sequences.md b/300_architecture/sequences/email_sequences.md index f25343c..f3c29aa 100644 --- a/300_architecture/sequences/email_sequences.md +++ b/300_architecture/sequences/email_sequences.md @@ -18,46 +18,50 @@ ## 1. Gmail OAuth 인증 -### 1.1 최초 Gmail 연결 (프론트엔드 시작) +### 1.1 최초 Gmail 연결 (프론트엔드 시작) - Gmail Passport 방식 ```mermaid sequenceDiagram participant User as 사용자 participant Front as 프론트엔드 - participant Gateway as Gateway(8100) participant Auth as auth-server(9000) participant Google as Google OAuth participant DB as PostgreSQL User->>Front: Gmail 연결 버튼 클릭 - Front->>Gateway: POST /api/auth/gmail/connect - Gateway->>Auth: 인증 요청 전달 + Note over Front: 현재 페이지 URL 저장 + Front->>Auth: GET /auth/gmail/passport + Note over Auth: ?user_id={userId}
&return_url={currentUrl} - Auth->>Auth: state 토큰 생성 - Auth->>DB: state 임시 저장 + Auth->>Auth: state 데이터 생성 + Note over Auth: {user_id, timestamp,
return_url} → JSON Auth->>Auth: OAuth URL 생성 Note over Auth: client_id, redirect_uri,
scopes, state 포함 - Auth-->>Gateway: OAuth URL 반환 - Gateway-->>Front: 리다이렉트 URL + Auth-->>Front: 302 Redirect to Google Front->>Google: 브라우저 리다이렉트 User->>Google: Google 계정 로그인 User->>Google: 권한 승인 Note over Google: gmail.send
gmail.readonly
gmail.modify - Google->>Auth: 인증 코드 콜백 - Note over Auth: /api/auth/gmail/callback + Google->>Auth: GET /auth/gmail/passport/callback + Note over Auth: ?code={auth_code}&state={state} - Auth->>DB: state 검증 + Auth->>Auth: state 파싱 및 검증 + Note over Auth: user_id, return_url 추출 Auth->>Google: 토큰 교환 요청 Google-->>Auth: access_token, refresh_token Auth->>DB: gmail_tokens 테이블 저장 Note over DB: user_id, email,
tokens (암호화),
scopes, metadata - Auth-->>Front: 인증 완료 리다이렉트 - Front->>Front: 성공 메시지 표시 + Auth->>Auth: 리다이렉트 URL 결정 + Note over Auth: return_url 있으면 해당 페이지
없으면 /game 기본값 + + Auth-->>Front: 302 Redirect + Note over Front: {return_url}?gmail=success
&email={email} + Front->>Front: 원래 페이지에서 성공 메시지 표시 ``` ### 1.2 Slack에서 Gmail 연결 diff --git a/troubleshooting/250901_happybell80_gmail_oauth_404_return_url_fix.md b/troubleshooting/250901_happybell80_gmail_oauth_404_return_url_fix.md new file mode 100644 index 0000000..5874ac8 --- /dev/null +++ b/troubleshooting/250901_happybell80_gmail_oauth_404_return_url_fix.md @@ -0,0 +1,144 @@ +# Gmail OAuth 404 에러 및 Return URL 구현 + +## 작성일: 2025-09-01 +## 작성자: happybell80 +## 관련 서비스: auth-server, frontend-customer + +--- + +## 18시 30분 - 문제 발견 + +### 문제 상황 +1. **Frontend 404 오류** + - Gmail OAuth 성공 후 `/settings/items` 페이지로 리다이렉트 + - 해당 라우트가 Frontend에 존재하지 않아 404 에러 발생 + - 실제 아이템 관리 페이지는 `/inventory` + +2. **UX 문제** + - OAuth 인증 후 `/inventory` 페이지로 이동 + - 사용자가 원래 있던 페이지로 돌아가려면 수동 이동 필요 + +### 원인 분석 +```typescript +// frontend-customer/src/App.tsx + // 존재 + // 존재하지 않음 + +// auth-server/app/providers/gmail_passport.py:223 +return RedirectResponse(f"https://ro-being.com/settings/items?gmail=success&email={email}") +// 잘못된 경로로 리다이렉트 +``` + +--- + +## 18시 45분 - 1차 수정: 404 에러 해결 + +### 수정 내용 +```python +# auth-server/app/providers/gmail_passport.py:223 +# 변경 전 +return RedirectResponse(f"https://ro-being.com/settings/items?gmail=success&email={email}") + +# 변경 후 +return RedirectResponse(f"https://ro-being.com/inventory?gmail=success&email={email}") +``` + +### 결과 +- 404 에러 해결 ✅ +- `/inventory` 페이지로 정상 리다이렉트 +- 하지만 여전히 원래 페이지로 돌아가지 못함 + +--- + +## 19시 00분 - 2차 수정: Return URL 구현 + +### 구현 전략 +1. OAuth 요청 시 현재 페이지 URL을 `return_url` 파라미터로 전달 +2. auth-server에서 state에 return_url 저장 +3. OAuth 콜백 처리 시 return_url로 리다이렉트 +4. return_url이 없으면 기본값 `/game` 사용 + +### 수정 내용 + +#### 1. Frontend - OAuth 요청에 return_url 추가 +```typescript +// frontend-customer/src/components/skills-items-panel.tsx:359-364 +// 변경 전 +const authUrl = `https://auth.ro-being.com/auth/gmail/passport?user_id=${userId}`; +sessionStorage.setItem('gmail_oauth_return_url', window.location.href); +window.location.href = authUrl; + +// 변경 후 +const currentUrl = window.location.href; +const authUrl = `https://auth.ro-being.com/auth/gmail/passport?user_id=${userId}&return_url=${encodeURIComponent(currentUrl)}`; +window.location.href = authUrl; +``` + +#### 2. auth-server - return_url 처리 추가 +```python +# app/providers/gmail_passport.py + +# 1) 발급 엔드포인트 수정 (line 58) +@router.get("/") +async def issue_passport(user_id: str = Query(...), return_url: str = Query(default=None)): + # state에 return_url 포함 + state_data = {"user_id": user_id, "timestamp": time.time()} + if return_url: + state_data["return_url"] = return_url + state = json.dumps(state_data) + +# 2) 콜백 처리 수정 (line 225-235) +# return_url이 있으면 해당 페이지로, 없으면 기본 페이지로 +return_url = state_data.get("return_url") +if return_url: + separator = "&" if "?" in return_url else "?" + redirect_url = f"{return_url}{separator}gmail=success&email={email}" +else: + redirect_url = f"https://ro-being.com/game?gmail=success&email={email}" + +return RedirectResponse(redirect_url) +``` + +--- + +## 19시 15분 - 배포 및 검증 + +### Git 커밋 +```bash +# auth-server +git commit -m "feat: OAuth 인증 후 이전 페이지로 자동 복귀 구현" + +# frontend-customer +git commit -m "feat: Gmail OAuth 요청 시 return_url 파라미터 추가" +``` + +### 테스트 시나리오 +1. `/game` 페이지에서 Gmail 연결 → OAuth 완료 → `/game` 복귀 ✅ +2. `/game001` 페이지에서 Gmail 연결 → OAuth 완료 → `/game001` 복귀 ✅ +3. return_url 없이 직접 접근 → OAuth 완료 → `/game` (기본값) ✅ + +--- + +## 교훈 + +### 개발 원칙 +1. **라우트 변경 시 양쪽 확인**: Frontend 라우트 변경 시 Backend 리다이렉트 경로도 함께 확인 +2. **UX 우선**: OAuth 같은 외부 플로우는 원래 페이지로 복귀가 기본 +3. **파라미터 전달**: state 파라미터를 활용한 컨텍스트 유지 + +### 기술적 포인트 +1. **URL 인코딩**: return_url은 반드시 `encodeURIComponent()` 처리 +2. **쿼리 파라미터 처리**: 기존 쿼리 있는 URL에 파라미터 추가 시 `?` vs `&` 구분 +3. **기본값 설정**: return_url 없을 때 합리적인 기본값 제공 + +### 문서 업데이트 +- `300_architecture/sequences/email_sequences.md`: Gmail Passport 플로우 추가 +- `300_architecture/380_authentication_system.md`: Gmail Passport 엔드포인트 문서화 + +--- + +## 참고 자료 +- 관련 PR: auth-server #fc94303, frontend-customer #26e7f70 +- 영향받는 파일: + - auth-server/app/providers/gmail_passport.py + - frontend-customer/src/components/skills-items-panel.tsx \ No newline at end of file