From 24afb6b5b7ed6adbf32d29c02aa427d0002d9f20 Mon Sep 17 00:00:00 2001 From: jaejo Date: Thu, 23 Jul 2026 14:17:33 +0900 Subject: [PATCH 1/2] fix: remove social login queryString --- .../handler/OAuth2LoginSuccessHandler.java | 9 +--- momogo-frontend/src/App.tsx | 11 +---- momogo-frontend/src/pages/LoginPage.tsx | 42 ++----------------- momogo-frontend/vite.config.ts | 4 +- 4 files changed, 9 insertions(+), 57 deletions(-) diff --git a/momogo-api/src/main/java/com/momogo/api/auth/handler/OAuth2LoginSuccessHandler.java b/momogo-api/src/main/java/com/momogo/api/auth/handler/OAuth2LoginSuccessHandler.java index 11bfb42..9463298 100644 --- a/momogo-api/src/main/java/com/momogo/api/auth/handler/OAuth2LoginSuccessHandler.java +++ b/momogo-api/src/main/java/com/momogo/api/auth/handler/OAuth2LoginSuccessHandler.java @@ -68,13 +68,8 @@ public void onAuthenticationSuccess( // 리프레시 토큰 보안 쿠키 추가(HttpOnly) jwtTokenProvider.addRefreshCookie(response, refreshToken); - // 프론트엔드(React) 특정 콜백 주소로 Access Token을 쿼리스트링에 실어 리다이렉트 - String targetUrl = UriComponentsBuilder.fromUriString(redirectUrl) - .queryParam("token", accessToken) - .build().toUriString(); - - log.info("[OAuth2LoginSuccessHandler] 소셜 로그인 성공"); - response.sendRedirect(targetUrl); + log.info("[OAuth2LoginSuccessHandler] 소셜 로그인 성공 - 쿠키 발급 완료"); + response.sendRedirect(redirectUrl); } catch (Exception e) { log.error("[OAuth2LoginSuccessHandler] 토큰 생성 및 리다이렉션 실패", e); diff --git a/momogo-frontend/src/App.tsx b/momogo-frontend/src/App.tsx index aa2474c..490db0b 100644 --- a/momogo-frontend/src/App.tsx +++ b/momogo-frontend/src/App.tsx @@ -29,15 +29,8 @@ const App: React.FC = () => { const checkSession = async () => { try { - // OAuth 소셜 로그인 콜백 URL 파라미터 처리 (?token=... 또는 ?error=...) - const urlParams = new URLSearchParams(window.location.search); - const oauthToken = urlParams.get('token') || urlParams.get('accessToken'); - if (oauthToken) { - window.history.replaceState({}, document.title, window.location.pathname); - } - - // /api/auth/refresh는 accessToken만 내려주고 user는 항상 null이라(백엔드 응답 스펙), - // 재발급 성공 후 /api/users/me로 실제 유저 정보를 따로 받아온다. + // 순수 쿠키 방식 (Cookie-Only Flow): URL 쿼리 파라미터에 토큰을 전혀 노출하지 않습니다. + // 백엔드가 리다이렉트 시 보낸 HttpOnly Refresh Cookie로 /api/auth/refresh를 호출하여 Access Token을 안전하게 발급받습니다. const response = await refresh(); if (response && response.accessToken) { const freshUser = await request('/api/users/me', { method: 'GET' }); diff --git a/momogo-frontend/src/pages/LoginPage.tsx b/momogo-frontend/src/pages/LoginPage.tsx index 99df2e2..ad7940b 100644 --- a/momogo-frontend/src/pages/LoginPage.tsx +++ b/momogo-frontend/src/pages/LoginPage.tsx @@ -142,45 +142,9 @@ export const LoginPage: React.FC = ({ onLoginSuccess, showToast } }; - // 소셜 로그인 처리 (구글/카카오) - 401/500 백엔드 OAuth 에러 진입 방지 - const handleSocialLogin = async (provider: 'google' | 'kakao') => { - setLoading(true); - setErrorMsg(null); - const providerName = provider === 'google' ? 'Google' : 'Kakao'; - try { - const oauthUrl = `/oauth2/authorization/${provider}`; - // 백엔드 소셜 OAuth 엔드포인트 사전 점검 (401/500 서버 에러 진입 차단) - const res = await fetch(oauthUrl, { method: 'GET', redirect: 'manual' }).catch(() => null); - if (res && (res.status === 401 || res.status === 500 || res.status === 404)) { - showToast(`[${providerName}] 소셜 설정 서버 준비 중입니다. 데모 계정으로 간편 로그인합니다.`, 'info'); - const dummyUser: UserResponse = { - id: `${provider}-user-${Date.now()}`, - name: `${providerName} 회원`, - email: `${provider}_user@momogo.com`, - role: 'USER', - banned: false, - profileImageUrl: '/basic.png', - createdAt: new Date().toISOString() - }; - onLoginSuccess(dummyUser); - return; - } - window.location.href = oauthUrl; - } catch { - showToast(`[${providerName}] 소셜 계정으로 간편 로그인합니다.`, 'info'); - const dummyUser: UserResponse = { - id: `${provider}-user-demo`, - name: `${providerName} 회원`, - email: `${provider}_user@momogo.com`, - role: 'USER', - banned: false, - profileImageUrl: '/basic.png', - createdAt: new Date().toISOString() - }; - onLoginSuccess(dummyUser); - } finally { - setLoading(false); - } + // 소셜 로그인 처리 (구글/카카오) + const handleSocialLogin = (provider: 'google' | 'kakao') => { + window.location.href = `/oauth2/authorization/${provider}`; }; return ( diff --git a/momogo-frontend/vite.config.ts b/momogo-frontend/vite.config.ts index b9fe968..5bdf109 100644 --- a/momogo-frontend/vite.config.ts +++ b/momogo-frontend/vite.config.ts @@ -9,11 +9,11 @@ export default defineConfig({ target: 'http://localhost:8080', changeOrigin: true, }, - '/oauth2': { + '/oauth2/authorization': { target: 'http://localhost:8080', changeOrigin: true, }, - '/login': { + '/login/oauth2/code': { target: 'http://localhost:8080', changeOrigin: true, }, From cb1782ed4e806f6a55fbbbc53648506bf272f777 Mon Sep 17 00:00:00 2001 From: jaejo Date: Thu, 23 Jul 2026 14:42:16 +0900 Subject: [PATCH 2/2] fix: fix CodeRabbit Review --- .../com/momogo/api/auth/handler/OAuth2LoginSuccessHandler.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/momogo-api/src/main/java/com/momogo/api/auth/handler/OAuth2LoginSuccessHandler.java b/momogo-api/src/main/java/com/momogo/api/auth/handler/OAuth2LoginSuccessHandler.java index 9463298..58bbee2 100644 --- a/momogo-api/src/main/java/com/momogo/api/auth/handler/OAuth2LoginSuccessHandler.java +++ b/momogo-api/src/main/java/com/momogo/api/auth/handler/OAuth2LoginSuccessHandler.java @@ -37,8 +37,7 @@ public class OAuth2LoginSuccessHandler implements AuthenticationSuccessHandler { * 3. 레지스트리 등록: 발급된 토큰 세트를 JwtRegistry에 등록하여 무효화 및 관리를 수행합니다. * 4. 보안 쿠키 설정: 탈취 위험이 높은 Refresh Token은 클라이언트 자바스크립트가 접근할 수 없도록 * HttpOnly, Secure 속성이 적용된 보안 쿠키에 탑재합니다. - * 5. 리다이렉트: 최종 성공 URL(app.oauth2.success-redirect-url) 뒤에 쿼리 파라미터(token=...)로 Access Token을 실어 리다이렉트(sendRedirect) 시킴으로써, - * 프론트엔드가 토큰을 즉시 획득할 수 있도록 합니다. + * 5. Refresh Cookie 발급 후 프론트엔드로 리다이렉트 * * @param request HttpServletRequest 요청 객체 * @param response HttpServletResponse 응답 객체