Skip to main content
  1. Guides 리스트/
  2. Next.js 답게 개발하기: 앱 라우터의 설계 원리와 실전 가이드/

Next.js 인증과 인가 완벽 가이드 이 방법만 아세요

·481 words·3 mins·
Next.js 답게 개발하기: 앱 라우터의 설계 원리와 실전 가이드 - This article is part of a series.
Part 20: This Article

Next.js에서 인증(Authentication) 상태를 유지하는 방법은 크게 두 가지인데요.

필요한 정보를 쿠키에 직접 저장하거나, 세션 ID만 쿠키에 담고 실제 데이터는 Redis 같은 곳에 저장하는 방식입니다.

그리고 인가(Authorization) 체크는 보통 ‘URL 기반 인가’와 ‘데이터 접근 인가’로 나뉘는데요.

Next.js에서는 특히 URL 기반 인가를 구현할 때 몇 가지 중요한 제약 사항을 반드시 알아야 합니다.

Next.js의 인증(Authentication)/인가(Authorization)는 왜 다를까
#

인증(Authentication)과 인가(Authorization)는 모든 웹 애플리케이션의 기본 중의 기본인데요.

하지만 Next.js에서는 기존 웹 프레임워크와는 다른, 몇 가지 독특한 제약 조건 속에서 이 기능들을 구현해야 합니다.

이는 Next.js가 컴포넌트의 병렬 실행을 중요하게 생각하는 RSC 아키텍처를 기반으로 하고, 여러 실행 환경(edge, Node.js)을 가지는 등 기존 프레임워크와는 근본적으로 다른 특징을 갖고 있기 때문입니다.

제약 1 페이지와 레이아웃은 병렬로 렌더링된다
#

Next.js에서는 layout.tsx를 사용해 여러 페이지에 공통 레이아웃을 적용할 수 있는데요.

‘그럼 /dashboard 하위의 모든 페이지에 대한 인가 체크를 layout.tsx에서 한 번에 처리하면 되겠네?‘라고 생각하기 쉽습니다.

하지만 이것은 아주 위험한 생각인데요.

Next.js에서는 페이지와 레이아웃이 ‘병렬’로 렌더링되기 때문에, 레이아웃의 인가 체크가 페이지보다 항상 먼저 실행된다는 보장이 없습니다.

만약 페이지 자체에 인가 체크 로직이 없다면, 의도치 않게 데이터가 유출될 수 있는 심각한 보안 허점이 생길 수 있습니다.

제약 2 서버 컴포넌트에서는 쿠키를 수정할 수 없다
#

이전 글에서도 강조했듯이, 서버 컴포넌트는 ‘순수성’을 지켜야 하므로 부수 효과를 일으키는 작업을 할 수 없는데요.

쿠키를 수정하는 것 역시 대표적인 부수 효과이기 때문에, 서버 컴포넌트 안에서는 쿠키를 수정할 수 없습니다.

쿠키 수정은 반드시 ‘서버 액션’이나 ‘라우트 핸들러’ 안에서만 해야 합니다.

제약 3 미들웨어의 제한적인 환경
#

Next.js의 미들웨어는 모든 요청을 가로채서 공통 로직을 처리할 수 있는 강력한 기능인데요.

하지만 v15.4 이전까지는 오직 ’edge’ 런타임에서만 실행되어서, Node.js API를 사용하거나 DB에 직접 접근하는 데 여러 제약이 있었습니다.

Next.js 인증/인가 설계의 핵심 포인트
#

이런 제약들을 고려했을 때, 우리는 크게 세 가지 포인트를 중심으로 인증/인가를 설계해야 하는데요.

바로 ‘인증 상태 유지’, ‘URL 인가’, ‘데이터 접근 인가’입니다.

인증 상태 유지하기
#

서버에서 인증 상태를 참조하려면 보통 쿠키를 사용하는데요.

JWT를 직접 쿠키에 저장하거나, 세션 ID(JWT 형태)만 쿠키에 담고 실제 세션 데이터는 Redis에 저장하는 방식이 일반적입니다.

저는 후자를 더 선호하는데요.

액세스 토큰 같은 민감한 정보를 브라우저에 직접 노출하지 않아 보안성이 높고, 쿠키 크기도 줄일 수 있다는 장점이 있습니다.

URL 인가 체크하기
#

URL 기반 인가는 보통 각 페이지 컴포넌트의 시작 부분에서 처리하게 되는데요.

공통화된 verifySession() 같은 함수를 만들어 호출하는 방식입니다.

// page.tsx
export default async function Page() {
  await verifySession(); // 인가 실패 시 /login으로 리디렉션

  // ...
}

만약 세션 데이터를 Redis 같은 외부 저장소에서 가져와야 한다면, 이 로직은 Node.js 런타임이 필요한 미들웨어에서 처리하거나, 위 코드처럼 각 페이지에서 개별적으로 처리해야 하는 번거로움이 있습니다.

데이터 접근 인가 체크하기
#

데이터 접근에 대한 인가 체크는, 데이터 페칭을 담당하는 ‘데이터 페칭 레이어’에서 구현하는 것이 가장 좋은데요.

예를 들어 유료 사용자만 접근할 수 있는 데이터가 있다면, 해당 데이터를 가져오는 함수 안에서 사용자 플랜을 확인하는 로직을 추가하는 방식입니다.

import { unauthorized } from "next/navigation";

export async function fetchPaidOnlyData() {
  if (!(await isPaidUser())) {
    unauthorized(); // 401 인증 에러 발생
  }

  // ...
}

이렇게 하면 인가 로직이 데이터와 가까운 곳에 위치하게 되어, 코드가 훨씬 더 명확하고 안전해집니다.

Next.js 답게 개발하기: 앱 라우터의 설계 원리와 실전 가이드 - This article is part of a series.
Part 20: This Article