iBetter Books
수정

Ch 01. 로그인이 필요한 이유 — 인증의 개념

도서관에 들어가려면 회원증을 보여줘야 합니다. 직원실에는 직원만 들어갈 수 있습니다. 특별 열람실에는 교수나 연구원만 입장 가능합니다. 이 세 가지 상황은 모두 비슷해 보이지만, 사실 다른 개념입니다.

첫 번째는 "당신이 누구인지" 확인하는 것이고, 두 번째와 세 번째는 "당신이 무엇을 할 수 있는지" 결정하는 것입니다.

인증과 인가 — 비슷하지만 다른 두 개념

인증(Authentication)은 신원 확인입니다. "당신이 정말 누구인가?"를 묻습니다. 로그인 과정이 바로 인증입니다. 이메일과 비밀번호를 입력하면 시스템이 "맞습니다, 당신은 홍길동이군요"라고 확인해줍니다.

인가(Authorization)는 권한 확인입니다. "당신이 이것을 할 수 있는가?"를 묻습니다. 로그인은 했지만 모든 기능을 쓸 수 있는 건 아닙니다. 일반 사용자는 다른 사람의 글을 삭제할 수 없고, 관리자 페이지에 접근할 수 없습니다.

인증: "당신은 홍길동입니까?" → 예/아니오인가: "홍길동이 이 페이지를 볼 수 있습니까?" → 예/아니오

인증 없이 인가는 없습니다. 누구인지 모르면 무엇을 허용할지 결정할 수 없습니다.

쿠키 기반 세션 vs JWT 토큰

사용자가 로그인에 성공했다면, 그 사실을 어떻게 기억할까요? HTTP는 본래 상태 없는(stateless) 프로토콜입니다. 각 요청은 독립적이고, 이전 요청을 기억하지 않습니다. 그래서 로그인 상태를 유지하려면 별도의 장치가 필요합니다.

쿠키 기반 세션

전통적인 방식입니다. 서버가 로그인 성공 시 세션 ID를 생성하고 서버 메모리(또는 데이터베이스)에 저장합니다. 그 세션 ID를 쿠키에 담아 브라우저에 보냅니다. 이후 요청마다 브라우저는 쿠키를 함께 보내고, 서버는 그 세션 ID로 사용자를 식별합니다.

로그인 → 서버가 세션 저장 → 세션 ID를 쿠키로 전달요청 → 브라우저가 쿠키 첨부 → 서버가 세션 ID로 사용자 조회

장점은 서버가 세션을 완전히 통제한다는 것입니다. 로그아웃 시 서버에서 세션을 삭제하면 즉시 효력이 사라집니다. 단점은 서버가 세션을 저장해야 하므로 서버 확장(scale-out) 시 세션 동기화 문제가 생깁니다.

JWT 토큰

현대적인 방식입니다. 서버가 로그인 성공 시 JWT(JSON Web Token)를 생성해 클라이언트에 보냅니다. 서버는 아무것도 저장하지 않습니다. 이후 요청마다 클라이언트가 JWT를 함께 보내고, 서버는 토큰의 서명을 검증해 사용자를 식별합니다.

로그인 → 서버가 JWT 생성(서명) → 클라이언트가 저장요청 → 클라이언트가 JWT 첨부 → 서버가 서명 검증 → 사용자 식별

장점은 서버가 상태를 저장하지 않아 수평 확장이 쉽다는 것입니다. 단점은 로그아웃해도 토큰이 만료되기 전까지 유효하다는 것입니다. (블랙리스트로 해결 가능하지만 복잡해집니다.)

구분 세션 방식 JWT 방식
저장 위치 서버 클라이언트
서버 부하 세션 조회 쿼리 발생 없음
즉시 무효화 가능 어려움
확장성 세션 동기화 필요 자유로움

Next.js에서 인증이 동작하는 위치

Next.js는 서버와 클라이언트가 혼재하는 환경입니다. 인증 역시 여러 곳에서 동작합니다.

Next.js 인증 동작 위치

미들웨어(middleware.ts): 가장 먼저 실행됩니다. 모든 요청이 페이지나 API에 도달하기 전에 통과하는 관문입니다. 여기서 미인증 사용자를 로그인 페이지로 리다이렉트하면, 서버 컴포넌트나 API가 실행되기 전에 차단할 수 있어 효율적입니다.

서버 컴포넌트: 페이지가 렌더링될 때 서버에서 세션을 확인합니다. 미들웨어를 통과했더라도 추가로 권한을 확인하거나, 사용자 정보를 가져와 렌더링에 활용합니다.

API 라우트 핸들러: 데이터를 변경하는 API는 반드시 서버에서 다시 인증을 확인해야 합니다. 클라이언트는 신뢰할 수 없습니다.

클라이언트 컴포넌트: 로그인 상태에 따라 UI를 다르게 보여줍니다. "로그인" 버튼 대신 "내 프로필"을 보여주거나, 작성자에게만 편집 버튼을 표시하는 것입니다.

미들웨어와 서버 컴포넌트에서 중복으로 확인하는 게 낭비처럼 보일 수 있습니다. 하지만 이는 의도적인 심층 방어(defense in depth)입니다. 미들웨어는 빠른 차단, 서버 컴포넌트는 세밀한 권한 확인을 담당합니다.

다음 챕터에서는 NextAuth.js를 사용해 실제 로그인 시스템을 구현합니다.