From 596349655aec867dbd205003043058fe37c114ad Mon Sep 17 00:00:00 2001 From: yeondon Date: Wed, 3 Jun 2026 17:45:44 +0900 Subject: [PATCH 1/3] =?UTF-8?q?refactor:=20OAuth=20redirectUri=20=EB=8F=99?= =?UTF-8?q?=EC=A0=81=20=EC=B2=98=EB=A6=AC=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Sonnet 4.6 --- .../src/pageContainer/CallbackPage/index.tsx | 14 ++++++++------ packages/api/src/hooks/auth/useOAuthLogin.ts | 10 ++++++++-- .../ui/src/components/LoginButton/index.tsx | 17 +---------------- 3 files changed, 17 insertions(+), 24 deletions(-) diff --git a/apps/client/src/pageContainer/CallbackPage/index.tsx b/apps/client/src/pageContainer/CallbackPage/index.tsx index 0445ae32..8468be89 100644 --- a/apps/client/src/pageContainer/CallbackPage/index.tsx +++ b/apps/client/src/pageContainer/CallbackPage/index.tsx @@ -22,10 +22,10 @@ const CallbackPage = ({ code, provider }: { code: string; provider: string }) => const handleLoginSuccess = async () => { await queryClient.invalidateQueries({ queryKey: memberQueryKeys.getMyMemberInfo() }); - const currentOrigin = window.location.origin; - const isStage = currentOrigin.includes('stage'); - const clientBaseUrl = isStage ? 'https://www.stage.hellogsm.kr' : 'https://www.hellogsm.kr'; - const nextUrl = provider === 'admin' ? `${clientBaseUrl}/?isAdmin=true` : clientBaseUrl; + const nextUrl = + provider === 'admin' + ? `${window.location.origin}/?isAdmin=true` + : window.location.origin; router.replace(nextUrl); }; @@ -59,10 +59,12 @@ const CallbackPage = ({ code, provider }: { code: string; provider: string }) => return; } + const redirectUri = `${window.location.origin}/callback`; + if (provider === 'google' || provider === 'admin') { - googleLogin(code); + googleLogin({ code, redirectUri }); } else if (provider === 'kakao') { - kakaoLogin(code); + kakaoLogin({ code, redirectUri }); } else { router.replace('/'); toast.error('로그인에 실패했습니다.'); diff --git a/packages/api/src/hooks/auth/useOAuthLogin.ts b/packages/api/src/hooks/auth/useOAuthLogin.ts index 503d51c2..c5526c86 100644 --- a/packages/api/src/hooks/auth/useOAuthLogin.ts +++ b/packages/api/src/hooks/auth/useOAuthLogin.ts @@ -9,11 +9,17 @@ interface ReturnDataType { message: string; } +interface LoginPayload { + code: string; + redirectUri: string; +} + export const useOAuthLogin = ( provider: 'google' | 'kakao', - options?: UseMutationOptions, + options?: UseMutationOptions, ) => useMutation({ - mutationFn: (code: string) => post(authUrl.postLogin(provider), { code }), + mutationFn: ({ code, redirectUri }: LoginPayload) => + post(authUrl.postLogin(provider), { code, redirectUri }), ...options, }); diff --git a/packages/ui/src/components/LoginButton/index.tsx b/packages/ui/src/components/LoginButton/index.tsx index 84fef142..0615335c 100644 --- a/packages/ui/src/components/LoginButton/index.tsx +++ b/packages/ui/src/components/LoginButton/index.tsx @@ -47,22 +47,7 @@ const LoginButton = React.forwardRef( React.useEffect(() => { if (typeof window !== 'undefined') { - const currentOrigin = window.location.origin; - - const stageOrigins = [ - 'http://localhost:3000', - 'http://localhost:3001', - 'https://www.stage.hellogsm.kr', - 'https://admin.stage.hellogsm.kr', - ]; - - const productionOrigins = ['https://www.hellogsm.kr', 'https://admin.hellogsm.kr']; - - if (stageOrigins.includes(currentOrigin)) { - setRedirectUri('https://www.stage.hellogsm.kr/callback'); - } else if (productionOrigins.includes(currentOrigin)) { - setRedirectUri('https://www.hellogsm.kr/callback'); - } + setRedirectUri(`${window.location.origin}/callback`); } }, []); From 7da301cc2a629c57411d771f8f9b18a37ec1a44a Mon Sep 17 00:00:00 2001 From: yeondon Date: Thu, 4 Jun 2026 03:13:03 +0900 Subject: [PATCH 2/3] =?UTF-8?q?fix:=20admin/calback=EC=9C=BC=EB=A1=9C=20?= =?UTF-8?q?=EC=9D=B4=EB=8F=99=ED=95=98=EB=8A=94=20=EB=B2=84=EA=B7=B8=20?= =?UTF-8?q?=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/ui/src/components/LoginButton/index.tsx | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/packages/ui/src/components/LoginButton/index.tsx b/packages/ui/src/components/LoginButton/index.tsx index 0615335c..3ced87ee 100644 --- a/packages/ui/src/components/LoginButton/index.tsx +++ b/packages/ui/src/components/LoginButton/index.tsx @@ -39,6 +39,11 @@ interface LoginButtonProps isAdmin?: boolean; } +const getClientOrigin = (origin: string): string => { + if (origin === 'http://localhost:3001') return 'http://localhost:3000'; + return origin.replace('://admin.', '://www.'); +}; + const LoginButton = React.forwardRef( ({ className, variant, children, isAdmin = false, ...props }, ref) => { const [redirectUri, setRedirectUri] = React.useState(''); @@ -47,9 +52,10 @@ const LoginButton = React.forwardRef( React.useEffect(() => { if (typeof window !== 'undefined') { - setRedirectUri(`${window.location.origin}/callback`); + const origin = isAdmin ? getClientOrigin(window.location.origin) : window.location.origin; + setRedirectUri(`${origin}/callback`); } - }, []); + }, [isAdmin]); React.useEffect(() => { if (redirectUri) { From c58871130301fcdcf9bb3424818241c1fee8982e Mon Sep 17 00:00:00 2001 From: yeondon Date: Mon, 8 Jun 2026 03:28:46 +0900 Subject: [PATCH 3/3] =?UTF-8?q?fix:=20=EC=96=B4=EB=93=9C=EB=AF=BC=20?= =?UTF-8?q?=EB=A1=9C=EA=B7=B8=EC=9D=B8=20=EC=8B=9C=20=ED=99=98=EA=B2=BD=20?= =?UTF-8?q?=ED=8C=90=EB=B3=84=20=EB=A1=9C=EC=A7=81=EC=9D=84=20origin/host?= =?UTF-8?q?=20=EA=B8=B0=EB=B0=98=EC=9C=BC=EB=A1=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit env 변수 기반 판별이 로컬에서도 stage API를 가리켜 잘못된 환경으로 분류되던 문제를 실제 요청 host와 origin을 기준으로 판별하도록 변경 Co-Authored-By: Claude Sonnet 4.6 --- apps/client/src/app/page.tsx | 9 +++++++-- packages/ui/src/components/LoginButton/index.tsx | 5 +++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/apps/client/src/app/page.tsx b/apps/client/src/app/page.tsx index a045566f..7b554a70 100644 --- a/apps/client/src/app/page.tsx +++ b/apps/client/src/app/page.tsx @@ -1,3 +1,4 @@ +import { headers } from 'next/headers'; import { redirect } from 'next/navigation'; import { MainPage } from '@/pageContainer'; @@ -24,8 +25,12 @@ export default async function Home({ searchParams }: { searchParams?: { isAdmin? const isAdminRole = authInfo?.role === 'ADMIN' || authInfo?.role === 'ROOT'; if (isAdminRequested && isAdminRole) { - const isStage = process.env.NEXT_PUBLIC_API_BASE_URL?.includes('stage'); - const adminUrl = isStage ? 'https://admin.stage.hellogsm.kr' : 'https://admin.hellogsm.kr'; + const host = headers().get('host') ?? ''; + const adminUrl = host.includes('localhost') + ? 'http://localhost:3001' + : host.includes('stage') + ? 'https://admin.stage.hellogsm.kr' + : 'https://admin.hellogsm.kr'; redirect(adminUrl); } diff --git a/packages/ui/src/components/LoginButton/index.tsx b/packages/ui/src/components/LoginButton/index.tsx index 3ced87ee..6aa2d668 100644 --- a/packages/ui/src/components/LoginButton/index.tsx +++ b/packages/ui/src/components/LoginButton/index.tsx @@ -40,8 +40,9 @@ interface LoginButtonProps } const getClientOrigin = (origin: string): string => { - if (origin === 'http://localhost:3001') return 'http://localhost:3000'; - return origin.replace('://admin.', '://www.'); + if (origin.includes('localhost')) return 'http://localhost:3000'; + if (origin.includes('stage')) return 'https://www.stage.hellogsm.kr'; + return 'https://www.hellogsm.kr'; }; const LoginButton = React.forwardRef(