RSS듀오랩스
Next.js

Next.js 16 Proxy(구 Middleware)와 인증

작성자
듀오랩스 대표·8분 읽기

Next.js 16 으로 올리면 middleware.ts 에 경고가 붙습니다. 파일 규칙 이름이 proxy 로 바뀌었다는 안내입니다. Proxy 문서의 첫 문장은 기능이 그대로라고 적습니다.

Starting with Next.js 16, Middleware is now called Proxy to better reflect its purpose. The functionality remains the same.

기능이 같다면 이름은 왜 바꿨을까요. 이 질문을 따라가면, 이 파일에 흔히 맡기던 일 하나가 원래부터 맡기면 안 되는 일이었다는 점이 보입니다.

미들웨어에서 로그인을 확인하면 앱이 보호된다는 생각

관리 화면을 만들 때 자주 쓰는 구조입니다.

// proxy.ts
export function proxy(request: NextRequest) {
  if (!request.cookies.get("session")) {
    return NextResponse.redirect(new URL("/login", request.url));
  }
}

export const config = { matcher: "/admin/:path*" };

/admin 아래 모든 요청이 이 함수를 먼저 지나고, 세션 쿠키가 없으면 로그인 화면으로 보냅니다. Express 의 미들웨어처럼 모든 요청 앞에 서는 문지기로 이해하면, 이 한 곳에서 관리 화면 전체의 인증이 끝난 것처럼 보입니다.

Next.js 는 이 이해를 이름 변경의 이유로 직접 짚습니다. proxy 레퍼런스의 이전 안내입니다.

The term "middleware" can often be confused with Express.js middleware, leading to a misinterpretation of its purpose.

이름이 말하는 자리: 앱 앞의 네트워크 경계

같은 문서는 새 이름을 이렇게 설명합니다.

The term "proxy" implies a network boundary in front of the app, which is how this feature behaves. It can run outside of your application's main runtime and handle requests before they reach your app.

proxy 는 앱 안의 처리 단계가 아니라 앱 앞의 네트워크 경계입니다. 요청이 앱에 닿기 전에 주소를 다시 쓰거나(rewrite), 다른 곳으로 보내거나(redirect), 헤더를 고치거나, 바로 응답합니다. 앱의 주 실행 환경 밖에서 돌 수도 있습니다.

문서가 꼽는 쓰임새도 이 자리에 맞습니다. 일부 페이지의 헤더 수정, A/B 테스트에 따른 rewrite, 요청 속성에 따른 redirect 입니다. 그리고 단순한 redirect 라면 proxy 보다 next.config.tsredirects 설정을 먼저 쓰라고 권합니다.

인증을 proxy 에만 맡기면 안 되는 이유

Proxy 가이드는 이 점을 분명히 적습니다.

While Proxy can be helpful for optimistic checks such as permission-based redirects, it should not be used as a full session management or authorization solution.

proxy 는 낙관적 확인에는 좋습니다. 쿠키가 아예 없는 사용자를 로그인 화면으로 빨리 보내는 일입니다. 하지만 세션이 유효한지, 이 사용자가 이 데이터에 접근해도 되는지를 판단하는 최종 장치가 되어서는 안 됩니다.

레퍼런스에는 구체적인 이유가 하나 더 있습니다. 서버 함수가 proxy 를 지나는 방식입니다.

Server Functions are not separate routes in this chain. They are handled as POST requests to the route where they are used, so a Proxy matcher that excludes a path will also skip Server Function calls on that path.

서버 함수는 자기 주소가 따로 없고, 그 함수를 쓰는 페이지의 경로로 가는 POST 요청으로 처리됩니다. 그래서 matcher 가 어떤 경로를 빼면 그 경로의 서버 함수 호출도 proxy 를 지나지 않습니다. 문서는 이어서 경고합니다. matcher 를 고치거나 서버 함수를 다른 경로로 옮기는 리팩터링이 조용히 proxy 의 보호를 없앨 수 있으니, 인증과 권한은 각 서버 함수 안에서 확인하라는 것입니다.

앞의 예에서 누군가 관리 기능 하나를 /dashboard 경로의 페이지로 옮겼다고 해 보겠습니다. matcher 는 여전히 /admin/:path* 이므로, 옮긴 페이지의 서버 함수는 proxy 를 지나지 않습니다. 코드 어디에도 오류가 나지 않고, 테스트도 로그인한 상태로 돌리면 통과합니다. 서버 함수 글에서 서버 함수를 「외부에서 호출되는 입구」라고 한 이유가 여기서 다시 드러납니다. 입구마다 자물쇠가 있어야 하고, 건물 앞 문지기는 보조 장치입니다.

proxy 에서 하면 안 되는 두 가지

문서는 proxy 에 대한 제약을 두 가지 더 적습니다.

첫째, 느린 데이터 조회. proxy 는 요청마다 앱 앞에서 실행되므로, 여기서 데이터베이스를 조회하면 모든 요청이 그만큼 늦어집니다. 세션의 유효성을 데이터베이스에서 확인하는 일은 proxy 가 아니라 페이지나 서버 함수, 데이터 접근 계층에서 합니다.

둘째, fetch 캐시 옵션. 문서에 따르면 proxy 안에서 fetchcache, next.revalidate, next.tags 를 줘도 효과가 없습니다. 앱의 캐시 체계 밖에 있기 때문입니다.

그리고 proxy 파일은 프로젝트에 하나만 둘 수 있습니다. 경로별로 로직이 다르면 모듈로 나눠 한 파일에서 불러 씁니다.

인증을 층별로 나누는 구조

정리하면 인증과 권한 확인은 층마다 역할이 다릅니다.

하는 일 빠지면
proxy 쿠키가 없는 요청을 로그인 화면으로 빨리 보냄 로그인 안 한 사람이 빈 관리 화면을 잠깐 봄 (불편)
페이지, 레이아웃 세션 확인 후 화면을 그림 화면이 그려짐 (데이터가 없으면 피해는 작음)
서버 함수, 데이터 접근 계층 세션과 대상에 대한 권한 확인 후 읽기, 쓰기 데이터가 새거나 바뀜 (사고)

아래로 갈수록 빠졌을 때의 피해가 큽니다. 그래서 반드시 있어야 하는 확인은 가장 아래층, 데이터를 실제로 읽고 쓰는 자리에 둡니다. proxy 의 확인은 사용자 경험을 위한 빠른 길이고, 없어도 보안이 무너지지 않게 짜는 것이 맞다고 봅니다.

이름이 미들웨어에서 proxy 로 바뀐 것은 이 층 구분을 이름에 담은 것이라고 이해합니다. 문서도 proxy 를 되도록 마지막 수단으로 쓰고, 더 나은 API 로 목적을 이룰 수 있게 하겠다는 방향을 적고 있습니다.

여기까지가 확실한 부분

미들웨어가 proxy 로 이름만 바뀌었다는 점, 이름을 바꾼 이유, 쓰임새와 redirects 권고, 인증과 권한의 완전한 해법으로 쓰지 말라는 문장, 서버 함수가 경로로 가는 POST 로 처리되어 matcher 에서 빠질 수 있다는 점, 느린 조회와 fetch 캐시 옵션의 제약, 파일이 하나라는 점은 Next.js 16 문서 기준입니다. 이전 버전에서 올릴 때 쓰는 codemod 도 문서에 있지만 이 글에서는 다루지 않았습니다.

이 게시글 공유하기

마지막 수정:

공유하실 때는 출처(Duolabs)와 원문 주소를 표시해 주세요.