Develop

Next.js Middleware로 인증 체크와 리다이렉트를 구현하는 방법

페이지 컴포넌트 렌더링에 앞서 호출되는 Next.js Middleware를 활용해, 인증 토큰 유효성 검사 및 비인가 유저 리다이렉트 흐름을 Edge Runtime 환경에 최적화하여 구현하는 비결을 다룹니다.

Next.jsMiddleware인증리다이렉트App Router
Next.js middleware.ts 파일에서 요청 쿠키로 토큰을 확인하고 미인증 사용자를 로그인 페이지로 리다이렉트하는 코드
  • ·middleware.ts: 프로젝트 루트(app과 같은 레벨)에 위치, 모든 요청 전에 실행
  • ·matcher: 미들웨어를 적용할 경로 패턴 지정, 매칭되지 않는 경로는 건너뜀
  • ·NextResponse.redirect: 다른 URL로 리다이렉트, NextResponse.next: 요청 통과
  • ·Edge Runtime에서 실행: Node.js API 일부 사용 불가, 가벼운 로직만 적합
Next.js 블로그 관리자 기능을 설계하면서 `/admin` 디렉토리 하위의 보안 통제를 고민했습니다. 처음엔 개별 페이지 컴포넌트 내부에서 마운트 시점에 토큰을 체크해 화면을 튕겨내도록 짰는데, 관리 페이지 개수가 점차 늘어날수록 중복 검증 코드가 불어나고 첫 로드 시 빈 화면이 찰나로 노출되는 불쾌한 UX를 겪었습니다. 이 로직을 루트 레벨의 `middleware.ts`로 통짜 리팩토링하여 깔끔하게 정리했습니다. 한편 미들웨어가 Node.js 런타임이 아닌 경량 'Edge Runtime' 기반으로 돌아간다는 생태계 한계를 간과한 채, 아무 생각 없이 무거운 `jsonwebtoken` 모듈을 불러다 썼다가 빌드 에러를 맞닥뜨리기도 했으나, 브라우저 스펙인 Web Crypto API 기반으로 설계된 `jose` 라이브러리로 수혈해 문제를 단번에 종식시켰습니다.

1. 미들웨어 아키텍처와 라우팅 감지

중복 코드를 제거하고 Next.js Middleware 인증 체계로 통합하는 이유

사용자가 어떤 URL을 입력해 사이트에 노크를 날렸을 때, HTML 파일이나 API 서버에 신호가 안착하기 전 게이트웨이처럼 동작하며 요청을 가로채 선처리할 수 있게 돕는 것이 바로 Next.js Middleware의 원리입니다. 프로젝트 app 경로와 동급 레벨 루트에 middleware.ts 파일을 한 장 심어주는 것만으로 작동을 개시하죠. 각 페이지 파일의 클라이언트 사이드 단에서 복잡하게 React 상태를 만들어 토큰을 체크하고 리다이렉트(Client Redirect)를 돌리게 되면, 네트워크 대기 시점에 사용자가 비인가 영역을 잠시 눈으로 목격하는 보안 취약점이 드러납니다. 미들웨어를 활용하면 서버 단 관문에서 미리 비로그인 상태를 칼같이 튕겨내므로, 보안 구멍을 예방하고 불필요한 번들 다운로드 비용도 방어해 줍니다.

적용 타겟 경로만 지정하는 Next.js Middleware matcher 설정 기법

미들웨어 내부에 아무런 필터 규칙을 기재하지 않으면 CSS, 이미지, 폰트 에셋을 긁어가는 수백 번의 정적 요청에까지 매번 미들웨어가 참견하여 성능을 현격히 갉아먹습니다. 이를 차단하기 위해 config 객체 내에 matcher 정규식 경로 리스트를 타이트하게 매핑해 주어야 합니다. /admin/:path* 와 같이 보완 장치가 시급한 고유 경로만 핀포인트로 잡아주고, 부정 lookahead 문법((?!_next/static|api|...).*)을 가미해 정적 빌드 산출물과 일반 백엔드 API 요청은 미들웨어 검사 대상에서 스킵하도록 설계하는 것이 속도와 로직 무결성을 동시에 다지는 정석 팁입니다.

2. 토큰 검증 및 다중 권한 보호

쿠키 토큰 유무를 검사하는 Next.js Middleware 인증 로직 구축하기

실제 게이트를 지키는 로직은 request.cookies.get('token') 명령으로 브라우저 쿠키 백에 저장된 JWT 자격 증명을 꺼내 드는 데서 시작됩니다. 만약 토큰 알맹이가 존재하지 않는다면, NextResponse.redirect() 함수를 소환해 유저를 바로 로그인창으로 밀어버립니다. 이때 센스 있는 개발자라면 로그인 주소 파라미터 뒤에 ?callbackUrl=/admin/posts 형태로 **이전 유저가 도달하려 했던 원천 경로를 저장 매핑해 전송하는** 처리를 해두는 것이 좋습니다. 로그인을 성공하자마자 원래 가려던 아티클 편집창으로 자동 포워딩시켜 주므로, 사소하지만 실무 사용성을 하늘과 땅 차이로 갈라놓는 핵심 UX 패턴입니다.

// middleware.ts
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';
import { jwtVerify } from 'jose'; // Edge Runtime 친화적 암호화 모듈

const SECRET_KEY = new TextEncoder().encode(process.env.JWT_SECRET);

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

  // 토큰 미보유 시 즉시 로그인 튕겨내고 callbackUrl 탑재
  if (!token) {
    const url = new URL('/login', request.url);
    url.searchParams.set('callbackUrl', pathname);
    return NextResponse.redirect(url);
  }

  try {
    // Web Crypto API 기반 jose 모듈로 토큰 신뢰성 체크
    await jwtVerify(token, SECRET_KEY);
    return NextResponse.next();
  } catch (err) {
    // 변조된 토큰 파기 처리 후 로그인 페이지 유도
    return NextResponse.redirect(new URL('/login', request.url));
  }
}

export const config = {
  matcher: ['/admin/:path*', '/dashboard/:path*'],
};

사용자 세분화 권한에 대응하는 Next.js Middleware 역할 제어법

단순 로그인 유무 판별을 지나 유저 등급(어드민, 일반 멤버 등)에 따라 노선 통제를 치고 싶을 때도 미들웨어의 payload 해체 기술이 동원됩니다. jwtVerify 가 복호화해 낸 토큰 청크의 payload.role 값을 발라내어, 일반 멤버 등급 사용자가 겁 없이 /admin 으로 진입하려고 찔러본 상황이라면 즉시 403 Forbidden 경고창을 표시하거나 메인 홈으로 돌려보내는 식이죠. 이런 권한 분기 매핑 로직은 설정 정보가 얽혀 파일이 뚱뚱해지기 쉬우므로, 허용 정책 경로 매트릭스 맵 객체를 코드 밖에 정갈히 격리 설계해 두면 리팩토링 관리 효율이 훨씬 아름다워집니다.

3. UX 최적화와 예외 트러블슈팅

이미 인증이 완료된 사용자의 Next.js Middleware 리다이렉트 역지정

인증 요새를 단단히 세우는 일 외에 UX 완성도를 높이기 위한 또 다른 포인트는, 이미 로그인을 정상으로 완료한 회원이 주소창에 수동으로 /login 이나 /signup 경로를 입력하고 재진입했을 때의 역처리(Reverse Redirect)입니다. 이미 로컬에 싱싱한 토큰이 박혀 있음에도 로그인 폼이 멀뚱히 노출되는 것은 대단히 투박한 서비스죠. 미들웨어 내부 조건절에 유효 토큰 감지 시 로그인창 요청을 사전에 낚아채어 메인 대시보드 화면(/dashboard)으로 튕겨 넘겨주는 안전 코드를 심어두면, 틈새 없는 매끄러운 화면 렌더링 체인을 달성할 수 있습니다.

무한 리다이렉트 루프 등 Next.js Middleware 자주 만나는 에러 해결법

미들웨어를 짜다가 가장 많이 범하는 자살골 버그가 바로 브라우저가 화면을 못 띄우고 무한 뺑뺑이를 도는 리다이렉션 루프(Infinite Redirect Loop) 현상입니다. /login 경로에 들어왔을 때도 미들웨어가 낚아채어 '토큰이 없네? /login 으로 가라!' 고 명령하고, 다시 들어오면 또 로그인창으로 튕겨내는 어리석은 연쇄 반응이죠. 이를 예방하려면 matcher 경로에서 /login 페이지를 완전히 발라내어 제외 처리하거나, 미들웨어 코드 본문 상단에 if (pathname === '/login') return NextResponse.next(); 와 같은 예외 탈출 가드 문구를 튼튼하게 박아주어야 합니다.

자주 묻는 질문

jsonwebtoken 모듈을 사용하려는데 빌드 에러 콘솔에 'The edge runtime does not support Node.js...' 문구가 뜹니다.+

Next.js 미들웨어는 V8 엔진 위에서 극단적인 고성능으로 기동되는 Edge Runtime 환경을 활용합니다. Node.js 내장 OS 종속 라이브러리에 기대어 개발된 `jsonwebtoken` 패키지는 가동이 거부되므로, 웹 표준 규격인 Web Crypto API 기반으로 이식된 `jose` 라이브러리를 채용하여 서명 검증을 이행하셔야 해결됩니다.

인증 후 원래 사용자가 접근하려다 튕겼던 타겟 페이지 주소로 바로 복귀시켜 주고 싶습니다.+

미들웨어 리다이렉트 분기문에서 `loginUrl.searchParams.set('callbackUrl', request.nextUrl.pathname)` 과 같이 URL 뒤편에 가려던 타겟 주소를 저장해 넘기세요. 그 후 로그인 폼 컴포넌트 측에서 성공 콜백 수신 즉시 쿼리스트링에 심어진 callbackUrl 경로를 읽어 그곳으로 밀어주면 우아하게 마감됩니다.

관련 글