diff options
Diffstat (limited to 'lib/auth/custom-signout.ts')
| -rw-r--r-- | lib/auth/custom-signout.ts | 78 |
1 files changed, 72 insertions, 6 deletions
diff --git a/lib/auth/custom-signout.ts b/lib/auth/custom-signout.ts index d59bd81c..6f3a6b01 100644 --- a/lib/auth/custom-signout.ts +++ b/lib/auth/custom-signout.ts @@ -11,19 +11,28 @@ interface CustomSignOutOptions { /** * 커스텀 로그아웃 함수 * - * @param options - callbackUrl: 로그아웃 후 이동할 URL (기본: 현재 origin + "/") + * @param options - callbackUrl: 로그아웃 후 이동할 URL (상대 경로 권장: "/ko/partners") * @param options - redirect: 자동 리다이렉트 여부 (기본: true) */ export async function customSignOut(options?: CustomSignOutOptions): Promise<void> { const { callbackUrl, redirect = true } = options || {}; + console.log('[customSignOut] 시작:', { + currentOrigin: window.location.origin, + currentHref: window.location.href, + callbackUrl, + redirect, + }); + try { // 1. CSRF 토큰 가져오기 const csrfResponse = await fetch('/api/auth/csrf'); const { csrfToken } = await csrfResponse.json(); - // 2. 서버에 로그아웃 요청 - await fetch('/api/auth/signout', { + console.log('[customSignOut] CSRF 토큰 획득'); + + // 2. 서버에 로그아웃 요청 (리다이렉트 방지) + const signoutResponse = await fetch('/api/auth/signout', { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded', @@ -32,18 +41,75 @@ export async function customSignOut(options?: CustomSignOutOptions): Promise<voi csrfToken, json: 'true', }), + redirect: 'manual', // ⭐ 서버의 리다이렉트를 자동으로 따라가지 않음 + }); + + console.log('[customSignOut] 서버 응답:', { + status: signoutResponse.status, + statusText: signoutResponse.statusText, + redirected: signoutResponse.redirected, + url: signoutResponse.url, }); - // 3. 리다이렉트 + // 3. NextAuth 세션 쿠키 즉시 삭제 (middleware가 감지하도록) + document.cookie = 'next-auth.session-token=; Path=/; Expires=Thu, 01 Jan 1970 00:00:01 GMT;'; + document.cookie = '__Secure-next-auth.session-token=; Path=/; Expires=Thu, 01 Jan 1970 00:00:01 GMT; Secure;'; + + console.log('[customSignOut] 세션 쿠키 삭제 완료'); + + // 4. 리다이렉트 if (redirect) { - const finalUrl = callbackUrl || window.location.origin; + // ⭐ URL 객체로 변환하여 상대 경로인지 확인 + let finalUrl: string; + + if (callbackUrl) { + try { + // callbackUrl이 절대 URL인 경우 (http:// 또는 https://로 시작) + if (callbackUrl.startsWith('http://') || callbackUrl.startsWith('https://')) { + const urlObj = new URL(callbackUrl); + // 같은 origin인 경우 pathname만 사용 (상대 경로로 변환) + if (urlObj.origin === window.location.origin) { + finalUrl = urlObj.pathname + urlObj.search + urlObj.hash; + } else { + finalUrl = callbackUrl; + } + } else { + // 이미 상대 경로인 경우 (/, /ko/partners 등) + finalUrl = callbackUrl; + } + } catch (error) { + console.error('[customSignOut] callbackUrl 파싱 오류:', error); + finalUrl = callbackUrl; // 오류 시 원본 사용 + } + } else { + // callbackUrl이 없는 경우 루트 경로로 + finalUrl = '/'; + } + + console.log('[customSignOut] 리다이렉트 실행:', finalUrl); window.location.href = finalUrl; } } catch (error) { console.error('Custom sign out error:', error); // 에러 발생 시에도 리다이렉트 (세션이 이미 만료되었을 수 있음) if (redirect) { - const finalUrl = callbackUrl || window.location.origin; + let finalUrl = '/'; + if (callbackUrl) { + try { + if (callbackUrl.startsWith('http://') || callbackUrl.startsWith('https://')) { + const urlObj = new URL(callbackUrl); + if (urlObj.origin === window.location.origin) { + finalUrl = urlObj.pathname + urlObj.search + urlObj.hash; + } else { + finalUrl = callbackUrl; + } + } else { + finalUrl = callbackUrl; + } + } catch { + finalUrl = callbackUrl; + } + } window.location.href = finalUrl; } } |
