From 34231782500c3df76770c057618e00a1f3dd3e84 Mon Sep 17 00:00:00 2001 From: kyy Date: Wed, 25 Feb 2026 09:09:18 +0900 Subject: [PATCH] =?UTF-8?q?SSO=20=EB=A1=9C=EA=B7=B8=EC=9D=B8=20=EB=B0=A9?= =?UTF-8?q?=EC=8B=9D=EC=9D=84=20=ED=8C=9D=EC=97=85=20=EA=B8=B0=EB=B0=98?= =?UTF-8?q?=EC=9C=BC=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 --- devfront/src/features/auth/AuthCallbackPage.tsx | 7 +++++++ devfront/src/features/auth/LoginPage.tsx | 12 +++++++++--- devfront/src/lib/apiClient.ts | 5 +++-- devfront/src/lib/auth.ts | 1 + 4 files changed, 20 insertions(+), 5 deletions(-) diff --git a/devfront/src/features/auth/AuthCallbackPage.tsx b/devfront/src/features/auth/AuthCallbackPage.tsx index 638a7924..339dade5 100644 --- a/devfront/src/features/auth/AuthCallbackPage.tsx +++ b/devfront/src/features/auth/AuthCallbackPage.tsx @@ -1,12 +1,19 @@ import { useEffect } from "react"; import { useAuth } from "react-oidc-context"; import { useNavigate } from "react-router-dom"; +import { userManager } from "../../lib/auth"; export default function AuthCallbackPage() { const auth = useAuth(); const navigate = useNavigate(); useEffect(() => { + // 팝업으로 열린 경우 signinPopupCallback 처리 + if (window.opener) { + userManager.signinPopupCallback(); + return; + } + if (auth.isAuthenticated) { navigate("/", { replace: true }); } else if (auth.error) { diff --git a/devfront/src/features/auth/LoginPage.tsx b/devfront/src/features/auth/LoginPage.tsx index 7004f4eb..4d592b68 100644 --- a/devfront/src/features/auth/LoginPage.tsx +++ b/devfront/src/features/auth/LoginPage.tsx @@ -1,5 +1,6 @@ import { ExternalLink, LogIn, ShieldHalf } from "lucide-react"; import { useAuth } from "react-oidc-context"; +import { useNavigate } from "react-router-dom"; import { Button } from "../../components/ui/button"; import { Card, @@ -11,10 +12,15 @@ import { function LoginPage() { const auth = useAuth(); + const navigate = useNavigate(); - const handleSSOLogin = () => { - // OIDC client-side authentication flow started here - auth.signinRedirect(); + const handleSSOLogin = async () => { + try { + await auth.signinPopup(); + navigate("/clients", { replace: true }); + } catch (error) { + console.error("Popup login failed", error); + } }; return ( diff --git a/devfront/src/lib/apiClient.ts b/devfront/src/lib/apiClient.ts index fd7cf54f..65a6995c 100644 --- a/devfront/src/lib/apiClient.ts +++ b/devfront/src/lib/apiClient.ts @@ -30,8 +30,9 @@ apiClient.interceptors.response.use( if (error.response?.status === 401) { // 401 발생 시 로그인 페이지로 리다이렉트 const isAuthPath = window.location.pathname.startsWith("/callback"); - if (!isAuthPath) { - userManager.signinRedirect(); + const isLoginPath = window.location.pathname === "/login"; + if (!isAuthPath && !isLoginPath) { + window.location.href = "/login"; } } return Promise.reject(error); diff --git a/devfront/src/lib/auth.ts b/devfront/src/lib/auth.ts index 90453199..f424d9d9 100644 --- a/devfront/src/lib/auth.ts +++ b/devfront/src/lib/auth.ts @@ -9,6 +9,7 @@ export const oidcConfig: AuthProviderProps = { response_type: "code", scope: "openid offline_access profile email", // offline_access for refresh token post_logout_redirect_uri: window.location.origin, + popup_redirect_uri: `${window.location.origin}/auth/callback`, userStore: new WebStorageStateStore({ store: window.localStorage }), automaticSilentRenew: true, };