summaryrefslogtreecommitdiff
path: root/lib/auth
diff options
context:
space:
mode:
Diffstat (limited to 'lib/auth')
-rw-r--r--lib/auth/custom-signout.ts78
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;
}
}