Feature: GitHub OAuth 2.0 로그인 시스템 구현 및 React Query 도입#10
Conversation
- @tanstack/react-query 설치 - GitHub OAuth API 상태 관리 개선 준비 - 향후 API 호출 최적화 및 캐싱 기능 활용 예정
- LoginPage: GitHub OAuth URL 생성 및 리다이렉트 기능 - AuthCallbackPage: OAuth 콜백 처리 및 상태 분기 로직 - React Query useMutation 적용으로 자동 상태 관리 - API 함수 분리 (lib/api.ts) - main.tsx에 QueryClientProvider 설정 OAuth 2.0 Authorization Code Flow 구현 - CSRF 보호를 위한 state 파라미터 검증 - 기존유저(200) vs 신규유저(210) 자동 분기 React Query 최적화 - OAuth API만 retry: false 설정으로 재시도 방지 - 일반 mutation은 retry: 2 유지 - 전역 QueryClient 설정 최적화
There was a problem hiding this comment.
Summary of Changes
Hello @woo-dev-log, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!
This pull request introduces a robust GitHub OAuth 2.0 login system, providing a streamlined and secure authentication experience. Concurrently, it integrates React Query as the primary library for API state management, which standardizes and optimizes data fetching, caching, and error handling throughout the application. These changes lay a solid foundation for future API interactions and user authentication flows.
Highlights
- GitHub OAuth 2.0 Integration: I've implemented the full client-side flow for GitHub OAuth 2.0. This includes generating the authorization URL and redirecting users from the login page, as well as handling the callback to process the authorization code and determine user status (existing or new user).
- React Query Adoption: I've integrated
@tanstack/react-queryto manage API state. This significantly improves data fetching, caching, and error handling. I've configured specific retry policies:retry: falsefor OAuth mutations to prevent re-attempts on authentication codes, andretry: 2for general API queries. - Enhanced Security & Architecture: To bolster security, I've implemented CSRF protection by validating the
stateparameter usingsessionStorage. Architecturally, I've refactored all API calls into a dedicatedsrc/lib/api.tsfile, enhancing organization and reusability across the application.
Using Gemini Code Assist
The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.
Invoking Gemini
You can request assistance from Gemini at any point in your pull request via creating an issue comment (i.e. comment on the pull request page) using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands.
| Feature | Command | Description |
|---|---|---|
| Code Review | /gemini review |
Performs a code review for the current pull request in its current state. |
| Pull Request Summary | /gemini summary |
Provides a summary of the current pull request in its current state. |
| Comment | @gemini-code-assist | Responds in comments when explicitly tagged, both in issue comments and review comments. |
| Help | /gemini help |
Displays a list of available commands. |
Customization
To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.
Limitations & Feedback
Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments or fill out our survey to provide feedback.
You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.
Footnotes
-
Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution. ↩
There was a problem hiding this comment.
Code Review
안녕하세요. GitHub OAuth 2.0 로그인 기능 구현 및 React Query 도입 PR 리뷰를 맡았습니다.
전반적으로 OAuth 2.0 인증 흐름을 잘 구현하셨고, React Query를 도입하여 API 상태 관리를 개선한 점이 인상적입니다. 코드 구조와 관심사 분리도 잘 이루어졌습니다.
다만, 몇 가지 개선점을 제안드리고자 합니다. 주로 보안 모범 사례, 타입 안정성 강화, 테스트 코드 작성, 코드 가독성 향상에 대한 내용입니다. 특히 .env 파일 관리 방식과 테스트 코드 부재는 프로젝트의 안정성과 보안을 위해 꼭 확인해주시면 좋겠습니다.
자세한 내용은 각 파일에 남긴 코멘트를 참고해주세요.
| export const fetchLogin = async (code: string) => { | ||
| const response = await fetch(`/api/auth/sign-in?code=${encodeURIComponent(code)}`, { | ||
| method: 'GET', | ||
| headers: { 'Content-Type': 'application/json' }, | ||
| }); | ||
|
|
||
| if (!response.ok) { | ||
| throw new Error(`GitHub 로그인 실패: ${response.status}`); | ||
| } | ||
|
|
||
| return { | ||
| status: response.status, | ||
| data: await response.json() | ||
| }; | ||
| }; No newline at end of file |
There was a problem hiding this comment.
fetchLogin 함수의 반환 타입에서 data가 any로 추론되고 있습니다. 이는 타입 안정성을 저해하며, 프로젝트 스타일 가이드에도 위배됩니다.1
백엔드 API의 응답 명세에 따라 명확한 타입을 정의하고 적용하여 코드의 안정성과 예측 가능성을 높이는 것을 권장합니다.
예시:
interface LoginResponseData {
accessToken: string;
isNewUser: boolean;
// ... 기타 백엔드에서 전달하는 데이터
}
export const fetchLogin = async (code: string): Promise<{
status: number;
data: LoginResponseData;
}> => {
// ... 함수 본문
};Style Guide References
Footnotes
| import { useMutation } from '@tanstack/react-query'; | ||
| import { fetchLogin } from '@/lib/api'; | ||
|
|
||
| export default function AuthCallbackPage() { |
There was a problem hiding this comment.
새로운 로그인 흐름과 관련된 중요한 로직이 추가되었지만, 이에 대한 자동화된 테스트가 없습니다. 스타일 가이드에 따라 모든 코드에 테스트를 추가해야 합니다.1
특히 AuthCallbackPage 컴포넌트는 code, state, error 파라미터에 따라 분기하는 로직이 있으므로, 각 케이스(성공, CSRF 에러, 인증 코드 없음 등)에 대한 단위/통합 테스트를 추가하여 안정성을 확보해야 합니다.
Style Guide References
Footnotes
| export const fetchLogin = async (code: string) => { | ||
| const response = await fetch(`/api/auth/sign-in?code=${encodeURIComponent(code)}`, { | ||
| method: 'GET', | ||
| headers: { 'Content-Type': 'application/json' }, |
| useEffect(() => { | ||
| const handleCallback = () => { | ||
| const code = searchParams.get('code'); | ||
| const error = searchParams.get('error'); | ||
| const state = searchParams.get('state'); | ||
|
|
||
| if (error) { | ||
| navigate('/login', { replace: true }); | ||
| console.error('GitHub OAuth 에러:', error); | ||
| return; | ||
| } | ||
|
|
||
| if (!code) { | ||
| navigate('/login', { replace: true }); | ||
| console.log('GitHub에서 인증 코드를 받지 못했습니다'); | ||
| return; | ||
| } | ||
|
|
||
| const storedState = sessionStorage.getItem('github_oauth_state'); | ||
| if (state !== storedState) { | ||
| navigate('/login', { replace: true }); | ||
| console.log('보안 검증 실패'); | ||
| return; | ||
| } | ||
|
|
||
| signInMutation.mutate(code); | ||
| sessionStorage.removeItem('github_oauth_state'); | ||
| } | ||
|
|
||
| handleCallback(); | ||
| }, [searchParams, navigate, signInMutation]); |
| if (error) { | ||
| navigate('/login', { replace: true }); | ||
| console.error('GitHub OAuth 에러:', error); | ||
| return; | ||
| } | ||
|
|
||
| if (!code) { | ||
| navigate('/login', { replace: true }); | ||
| console.log('GitHub에서 인증 코드를 받지 못했습니다'); | ||
| return; | ||
| } | ||
|
|
||
| const storedState = sessionStorage.getItem('github_oauth_state'); | ||
| if (state !== storedState) { | ||
| navigate('/login', { replace: true }); | ||
| console.log('보안 검증 실패'); | ||
| return; | ||
| } |
| import { Button } from "@/components/ui/button"; | ||
|
|
||
| export function LoginPage() { | ||
| const handleGitHubLogin = async () => { |
| export function LoginPage() { | ||
| const handleGitHubLogin = async () => { | ||
| try { | ||
| const clientId = import.meta.env.VITE_GITHUB_CLIENT_ID;; |
| const githubAuthUrl = `https://github.com/login/oauth/authorize?` + | ||
| `client_id=${clientId}&` + | ||
| `redirect_uri=${encodeURIComponent(redirectUri)}&` + | ||
| `scope=${scope}&` + | ||
| `state=${state}`; |
There was a problem hiding this comment.
URL 쿼리 문자열을 문자열 접합으로 구성하고 있습니다. URLSearchParams 객체를 사용하면 코드가 더 간결해지고, 각 파라미터가 자동으로 URL 인코딩되어 안정성도 높아집니다.
const params = new URLSearchParams({
client_id: clientId,
redirect_uri: redirectUri,
scope: scope,
state: state,
});
const githubAuthUrl = `https://github.com/login/oauth/authorize?${params.toString()}`;- API 응답 타입을 Union 타입으로 확장하여 풍부한 데이터 활용 - 커스텀 훅 분리로 비즈니스 로직과 UI 관심사 분리 - 불필요한 try-catch 제거 및 환경변수 검증 추가 - 코드 가독성, 타입 안전성, 재사용성 모두 향상
- .env, .env.local, .env*.local 파일들 Git 추적 제외
API URL 환경변수 설정 - VITE_API_BASE_URL로 API 서버 분리 무한 호출 버그 수정 - useEffect 의존성에서 signInMutation 제거 - useMutation 객체 재생성으로 인한 무한 루프 해결 OAuth 보안 검증 강화 - 성공 시에만 state 삭제하여 재시도 가능성 보장 - API 실패 상황에서도 안전한 state 관리
- hasProcessed 플래그 추가로 일회용 코드 안전 처리 - 백엔드 중복 요청 이슈 해결
- 사용자 정보 구조 타입스크립트 인터페이스 정의 - OAuth 응답에 User 타입 적용으로 타입 안전성 향상
- token에서 accessToken, sessionId로 분리하여 정교한 인증 관리 - localStorage에 access_token, session_id 개별 저장
…se/Comeet_FE into feature/auth-login
…ack-devcourse/Comeet_FE into feature/auth-login
📌 PR 종류 (PR Type)
📝 요약 (Summary)
GitHub OAuth 2.0 기반 로그인 시스템 구현 및 React Query 도입으로 개발자 친화적 인증 환경 구축
🔍 상세 내용 (Describe your changes)
GitHub OAuth 2.0 로그인 시스템 구현
React Query 통합 및 상태 관리 자동화
아키텍처 개선
보안 및 사용자 경험 강화
📸 스크린샷 (필수)
✅ 확인 사항 (CheckList)
💬 기타 참고사항 (Optional)