Fix: 인증 콜백 처리 개선 및 프로젝트 문서 추가
app/auth/callback/route.ts - NextRequest 타입 사용으로 요청/URL 파라미터 처리 개선 - 에러 파라미터 초기 처리 추가 및 사용자 메시지 매핑 - Supabase 코드 교환 흐름 정리(성공/실패 처리 분리), 로컬/프록시 환경에 따른 리다이렉트 로직 보강 - 잘못된 접근(인증 링크 오류) 처리 추가 및 로깅 개선 AGENTS.md - 개발 규칙, 명령어, 설명 방식 등 에이전트용 가이드 문서 추가 (한국어 규칙 포함) PROJECT_CONTEXT.md - 프로젝트 기술 스택, 폴더 구조, 주요 규칙 및 작업 흐름을 정리한 기준 문서 추가
This commit is contained in:
@@ -1,20 +1,33 @@
|
||||
import { createClient } from "@/utils/supabase/server";
|
||||
import { NextResponse } from "next/server";
|
||||
import { type NextRequest, NextResponse } from "next/server"; // NextRequest 추가
|
||||
import { AUTH_ERROR_MESSAGES, AUTH_ROUTES } from "@/features/auth/constants";
|
||||
import { getAuthErrorMessage } from "@/features/auth/errors";
|
||||
|
||||
/**
|
||||
* OAuth/??? ?? ?? ??
|
||||
* OAuth/이메일 인증 콜백 처리
|
||||
*
|
||||
* Supabase 인증 후 리다이렉트되는 라우트입니다.
|
||||
* - 인증 코드를 세션으로 교환합니다.
|
||||
* - 인증 에러를 처리합니다.
|
||||
* - 최종 목적지(Next URL)로 리다이렉트합니다.
|
||||
*/
|
||||
export async function GET(request: Request) {
|
||||
const { searchParams, origin } = new URL(request.url);
|
||||
export async function GET(request: NextRequest) {
|
||||
// --------------------------------------------------------------------------
|
||||
// 1. 요청 파라미터 및 URL 준비
|
||||
// --------------------------------------------------------------------------
|
||||
const requestUrl = request.nextUrl.clone(); // URL 조작을 위해 복제
|
||||
const code = requestUrl.searchParams.get("code");
|
||||
const next = requestUrl.searchParams.get("next") ?? AUTH_ROUTES.HOME;
|
||||
|
||||
const code = searchParams.get("code");
|
||||
const next = searchParams.get("next") ?? AUTH_ROUTES.HOME;
|
||||
const error = searchParams.get("error");
|
||||
const error_code = searchParams.get("error_code");
|
||||
const error_description = searchParams.get("error_description");
|
||||
// 에러 파라미터 확인
|
||||
const error = requestUrl.searchParams.get("error");
|
||||
const error_code = requestUrl.searchParams.get("error_code");
|
||||
const error_description = requestUrl.searchParams.get("error_description");
|
||||
const origin = requestUrl.origin;
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// 2. 초기 에러 처리 (Provider 레벨 에러)
|
||||
// --------------------------------------------------------------------------
|
||||
if (error) {
|
||||
console.error("Auth callback error parameter:", {
|
||||
error,
|
||||
@@ -30,31 +43,46 @@ export async function GET(request: Request) {
|
||||
message = AUTH_ERROR_MESSAGES.OAUTH_SERVER_ERROR;
|
||||
}
|
||||
|
||||
// 로그인 페이지로 에러와 함께 이동
|
||||
return NextResponse.redirect(
|
||||
`${origin}${AUTH_ROUTES.LOGIN}?message=${encodeURIComponent(message)}`,
|
||||
);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// 3. 인증 코드 교환 (Supabase 공식 패턴 적용)
|
||||
// --------------------------------------------------------------------------
|
||||
if (code) {
|
||||
const supabase = await createClient();
|
||||
|
||||
// 코드 교환 실행
|
||||
const { error: exchangeError } =
|
||||
await supabase.auth.exchangeCodeForSession(code);
|
||||
|
||||
if (!exchangeError) {
|
||||
const forwardedHost = request.headers.get("x-forwarded-host");
|
||||
// ----------------------------------------------------------------------
|
||||
// 3-1. 교환 성공: 리다이렉트 처리
|
||||
// 코드 파라미터 등을 제거하고 깨끗한 URL로 이동합니다.
|
||||
// ----------------------------------------------------------------------
|
||||
const forwardedHost = request.headers.get("x-forwarded-host"); // 로드밸런서 지원
|
||||
const isLocalEnv = process.env.NODE_ENV === "development";
|
||||
|
||||
// 리다이렉트할 최종 URL 설정
|
||||
if (isLocalEnv) {
|
||||
// 로컬 개발 환경
|
||||
return NextResponse.redirect(`${origin}${next}`);
|
||||
} else if (forwardedHost) {
|
||||
// 프로덕션 환경 (Vercel 등 프록시 뒤)
|
||||
return NextResponse.redirect(`https://${forwardedHost}${next}`);
|
||||
} else {
|
||||
// 기본
|
||||
return NextResponse.redirect(`${origin}${next}`);
|
||||
}
|
||||
|
||||
if (forwardedHost) {
|
||||
return NextResponse.redirect(`https://${forwardedHost}${next}`);
|
||||
}
|
||||
|
||||
return NextResponse.redirect(`${origin}${next}`);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// 3-2. 교환 실패: 에러 처리
|
||||
// ------------------------------------------------------------------------
|
||||
console.error("Auth exchange error:", exchangeError.message);
|
||||
const message = getAuthErrorMessage(exchangeError);
|
||||
return NextResponse.redirect(
|
||||
@@ -62,6 +90,9 @@ export async function GET(request: Request) {
|
||||
);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// 4. 잘못된 접근 처리
|
||||
// --------------------------------------------------------------------------
|
||||
const errorMessage = encodeURIComponent(
|
||||
AUTH_ERROR_MESSAGES.INVALID_AUTH_LINK,
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user