Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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 응답 객체
Expand Down Expand Up @@ -68,13 +67,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);
Comment thread
coderabbitai[bot] marked this conversation as resolved.

} catch (Exception e) {
log.error("[OAuth2LoginSuccessHandler] 토큰 생성 및 리다이렉션 실패", e);
Expand Down
11 changes: 2 additions & 9 deletions momogo-frontend/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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<UserResponse>('/api/users/me', { method: 'GET' });
Expand Down
42 changes: 3 additions & 39 deletions momogo-frontend/src/pages/LoginPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -142,45 +142,9 @@ export const LoginPage: React.FC<LoginPageProps> = ({ 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 (
Expand Down
4 changes: 2 additions & 2 deletions momogo-frontend/vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
},
Expand Down