고민보단 실천을

Next.js middleware 인증 구현: 로그인 리다이렉트 루프와 matcher 실수 방지 본문

카테고리 없음

Next.js middleware 인증 구현: 로그인 리다이렉트 루프와 matcher 실수 방지

Just-Do-It 2026. 3. 3. 20:59

Next.js middleware 인증 구현: 로그인 리다이렉트 루프와 matcher 실수 방지

Next.js에서 인증을 붙일 때 가장 많이 검색되는 문제는 '무한 리다이렉트(redirect loop)'입니다. 원인은 대부분 matcher 범위와 예외 경로(로그인/정적 자원)가 엇갈리는 경우입니다. 이 글은 App Router 기준으로 middleware 인증을 안전하게 구성하는 체크리스트를 제공합니다.

Next.js middleware 인증 구현: 로그인 리다이렉트 루프와 matcher 실수 방지
middleware는 요청 초입에서 분기합니다. matcher와 예외 경로가 핵심입니다.

옵션/핵심 요소(3~6개)

항목의미언제 쓰는지(실무 상황)
matcher미들웨어 적용 경로정적 리소스/로그인 페이지를 제외해 루프 방지
public routes인증 없이 허용할 경로로그인/회원가입/헬스체크는 항상 통과
API 분리페이지 vs API 응답 분리페이지는 redirect, API는 401 JSON이 디버깅에 유리
next 파라미터로그인 후 원래 경로 복귀로그인 후 UX를 유지
쿠키/세션 확인인증 판단 근거서버에서 검증 가능한 세션값으로 판단

예시 코드

// middleware.ts
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'

const publicPaths = ['/login', '/signup', '/health']
function isPublic(pathname: string) {
return publicPaths.some((p) => pathname === p || pathname.startsWith(p + '/'))
}

export function middleware(req: NextRequest) {
const { pathname } = req.nextUrl
if (isPublic(pathname)) return NextResponse.next()

const session = req.cookies.get('session')?.value
const isAuthed = Boolean(session)

if (pathname.startsWith('/api') && !isAuthed) {
return NextResponse.json({ message: 'Unauthorized' }, { status: 401 })
}

if (!isAuthed) {
const url = req.nextUrl.clone()
url.pathname = '/login'
url.searchParams.set('next', pathname)
return NextResponse.redirect(url)
}
return NextResponse.next()
}

export const config = { matcher: ['/((?!_next/static|_next/image|favicon.ico|robots.txt).*)'] }

문제 상황(정확히 1개)

상황: /login으로 들어가도 다시 /login으로 계속 redirect되어 화면이 안 뜬다

원인: matcher/login에도 적용되고, '인증 없으면 /login' 로직이 자기 자신을 다시 redirect한다

해결: 로그인/회원가입 같은 public route를 먼저 예외 처리하고, 정적 리소스는 matcher에서 제외한다

예방 팁: 미들웨어는 항상 '예외 경로 → API 처리 → 페이지 redirect' 순으로 분기하고, 예외 경로 목록을 테스트로 고정한다

참고/출처

Comments