어제의 나보다 성장한 오늘의 나

[Next.js] Middleware를 활용한 인증 처리 통합 본문

Next.js

[Next.js] Middleware를 활용한 인증 처리 통합

today_me 2025. 7. 6. 22:10

기존 인증 로직 관리 문제

프로젝트 내 인증 및 권한 검사 로직이 각 페이지와 API 핸들러에 흩어져 있었습니다.

  • 각 페이지마다 인증/인가 처리를 하고 있으며,
  • API 보호를 위해 각 handler 내부에 반복적으로 인증 검사를 호출하고 있었습니다.

이런 방식은 새 기능을 추가할 때마다 중복 로직이 추가되고, 또 로직이 흩어져 있어서 관리도 어렵습니다.

그래서 요청이 들어오는 가장 앞단, 즉 middleware에서 인증을 일괄 처리해보기로 했습니다.
이렇게 하면 인증에 대한 처리를 각 페이지나 API에서 따로 신경 쓰지 않아도 되는 장점이 있습니다.


Middleware으로 기존 로직 마이그레이션

우선 기존의 접근 제어 로직을 middleware.ts에 그대로 옮겨 적용해봤습니다.

 

middleware.ts

export async function middleware(request: NextRequest) {
  const token = request.cookies.get("token")?.value;

  if (!token) {
    return NextResponse.redirect(new URL("/logout", request.url));
  }

  try {
    const payload = await verifyToken(token);

    const hasPermission = checkPermission({
      path: request.nextUrl.pathname,
      role: payload.role,
      permissions: payload.permissions,
    });

    if (!hasPermission) {
      return NextResponse.redirect(new URL("/forbidden", request.url));
    }

    return NextResponse.next();
  } catch {
    return NextResponse.redirect(new URL("/logout", request.url));
  }
}


그러나 실행과 동시에 다음과 같은 에러가 발생했습니다.

Error: The edge runtime does not support Node.js 'crypto' module.  

 

이 때부터 뭔가 쉽지 않겠다는 생각이 들었습니다...

열심히 알아보니 middleware에는 독특한 특징이 있었습니다.

 

Middleware는 next 서버 (node runtime) 와는 다르게 edge runtime 위에서 동작합니다.
https://nextjs.org/docs/app/api-reference/edge

 

Edge Runtime이란?

  • Node.js가 아닌 Web API 기반의 경량 실행 환경
  • 빠르고 가볍지만, Node 내장 모듈을 사용할 수 없고 사용 가능 API가 제한 적임

즉, 기존에 사용하던 MongoDB 클라이언트, node-cache, createHash 같은 기능을 지원하지 않습니다.

*edge에서 지원하는 API들
https://nextjs.org/docs/app/api-reference/edge#reference

 

그럼 기존 로직을 그대로 사용하는 것은 어려워 보이는데 어떻게 해결할 수 있을까??

 

시도 1: Middleware를 Node.js 런타임으로 전환

Next.js의 canary 버전에서는 middleware의 runtime을 'nodejs'로 설정할 수 있습니다.

 

 

middleware.ts

export const config = {
  runtime: "nodejs", // Canary 버전에서만 지원
};


이렇게 하면 Node 전용 API를 사용할 수 있어 기존 로직으로 구현할 수 있습니다.
그러나 canary는 실험적이기 때문에 안정성이 떨어지고, production에서는 사용이 권장되지 않아 보류하였습니다.

 

시도 2: Edge-safe 방식으로 구현


이슈 1) JWT 라이브러리 사용 제약
많은 JWT 라이브러리(예: jsonwebtoken)는 Node.js 전용 API에 의존하고 있어 Edge Runtime에서 사용할 수 없습니다.
-> 그러나 다행히 현재 사용중인 jose는 Edge 환경에서도 지원됩니다.

 


이슈 2) Node.js 내장 모듈 사용 불가 (node:crypto, node:cache 등)
Edge Runtime에서는 node:crypto 등 Node 고유 모듈을 사용할 수 없습니다.
-> Web Crypto API를 사용하여 해시, 암호화 등의 기능을 대체할 수 있습니다.

 

const hashBuffer = await crypto.subtle.digest(
  "SHA-256",
  new TextEncoder().encode("hello")
);

 

 

 

이슈 3) MongoDB 클라이언트 사용 불가
기존에는 JWT 검증을 위해 JWK 키를 MongoDB에서 가져오는 구조였지만, Edge 환경에서는 DB 클라이언트가 동작하지 않아 직접적인 DB 접근이 불가능합니다.
-> JWK 키를 /api/jwks 같은 endpoint에 공개하고, middleware에서 fetch()를 통해 가져오는 방식으로 개선할 수 있습니다. 이는 엔터프라이즈 환경에서 JWK 키가 외부에 노출된다는 우려가 있긴 합니다.

현 상황에서 Edge-safe 방식의 단점

위와 같이 구현하면 Edge-safe 방식으로도 가능은 하지만,

  • 여러 인증 로직을 직접 Edge 환경에 맞게 재구현해야 하고,
  • middleware의 책임이 지나치게 커진다는 단점이 있습니다.

 

“어차피 fetch를 활용 할 거면, 로직 자체를 Route handler에 위임하는 게 더 낫지 않을까?”

 

 

시도 3: 토큰 검증 로직을 Route handler로 위임 ✅

  •  middleware.ts: 토큰 유무 판단 및 리다이렉트 처리만 수행
  • Route Handler (/api/auth): JWT 서명 검증, 권한 검사 등 핵심 로직 처리

 

middleware.ts

export async function middleware(req: NextRequest) {
  const token = req.cookies.get("token")?.value;
  const pathname = req.nextUrl.pathname;

  if (!token) {
    return NextResponse.redirect(new URL("/logout", req.url));
  }

  const authResult = await fetch(`{NEXT_BASE_URL}/api/auth`, {
    method: "POST",
    headers: {
      Cookie: token,
    },
    body: JSON.stringify({
      pathname,
    }),
  });

  if (authResult.status === 401) {
    return NextResponse.redirect(new URL("/logout", req.url));
  } else if (authResult.status === 403) {
    return NextResponse.redirect(new URL("/forbidden", req.url));
  }
  return response;
}

 

 

장점

  • middleware는 요청 흐름만 제어 → 코드가 간단하고 가독성 높음
  • 인증 로직은 Node.js 환경에서 자유롭게 구현 가능
  • JWK를 기존처럼 외부에 노출할 필요 없음

 

최종 결정 및 요약

현재 상황에서는 토큰 검증 로직을 Route handler로 위임하는 방식이 가장 현실적이고 적합하다고 판단했습니다.
핵심 인증/권한 로직은 그대로 유지하면서도, Edge 환경의 제약을 피할 수 있기 때문입니다.

Next.js App Router의 middleware는 인증 흐름을 통일하는 데 효과적인 도구입니다.
하지만 Edge Runtime이라는 제약 조건 때문에 Node.js 고유 기능들을 사용할 수 없으므로, 모든 인증 로직을 middleware 내부에서 처리하기에는 한계가 있습니다.

따라서 우리는 다음과 같은 구조를 선택했습니다:
  • middleware: 요청 흐름을 제어 (토큰 유무 판단, 리다이렉트 등)
  • Route handler (/api/auth): Node.js 환경에서 실제 토큰 검증 및 권한 판단 수행

향후에 Next.js에서 정식 릴리즈에서 middleware의 Node.js runtime 지원이 될 수 있다고 하니 지켜 봐야겠습니다 :)

Comments