추가 인증 요구사항 분석
지난 강의들을 통해 로그인, 로그아웃, 사용자 생성 기능을 구현했다. 또한 특정 페이지를 보호하고, 로그인 여부에 따라 접근 가능한 페이지를 제어하는 방법도 다루었다. 예를 들어 프로필 페이지는 로그인하지 않은 상태에서는 접근할 수 없도록 리다이렉트 처리했다.
이 모든 기능은 Next Auth 패키지와 세션 관리 기능을 통해 작동한다. 여기서 말하는 '세션'은 Next Auth가 자동으로 관리하는 JSON Web Token(JWT)을 의미한다. 이 토큰은 브라우저 쿠키에 저장되며, Next Auth는 이 쿠키를 확인하여 활성 세션 여부를 판단한다. 프론트엔드에서 getSession을 호출하거나 useSession 훅을 사용할 때 일어나는 일이 바로 이 쿠키 확인 과정이다.
하지만 현재 상태에서는 중요한 기능 하나가 빠져 있다. 바로 API 라우트 보호다. 클라이언트 사이드에서 페이지 접근을 막는 것은 사용자 경험(UX) 측면에서 좋지만, 보안적으로는 불충분하다. 실제 중요한 것은 사용자가 수행할 수 있는 '작업'이다.
예를 들어 온라인 쇼핑몰을 구축한다고 가정해보자. 로그인한 사용자만 상품을 생성, 삭제, 관리할 수 있어야 한다. 웹사이트 인터페이스 뒤단에서는 API 엔드포인트로 요청을 보내 제품 생성이나 삭제 같은 작업을 트리거한다. 이때 해당 요청이 인증된 사용자로부터 왔는지 반드시 확인해야 한다.
UI를 완벽하게 제어하더라도, API 요청은 웹사이트를 거치지 않고 Postman과 같은 도구나 커맨드 라인을 통해 직접 전송될 수 있다. 따라서 클라이언트 사이드 보호뿐만 아니라, API 라우트 내부에서도 들어오는 요청을 검증하고 인증된 소스에서 온 것인지 확인하는 절차가 필수적이다. 이는 인증 시스템의 서버 사이드 측면이며 매우 중요한 부분이다.
API 라우트 보호 구현
API 라우트를 보호하는 방법을 알아보기 위해 비밀번호 변경(Change Password) 기능을 예로 들어보겠다. 비밀번호 변경은 명백히 제한되어야 하는 작업이며, 인증된 사용자만 수행할 수 있어야 한다.
이를 위해 pages/api/user 폴더에 change-password.js 파일을 생성한다. (api/auth 폴더가 아닌 곳에도 API 라우트를 만들 수 있음을 보여주기 위함이다.) 이 파일에서는 [...nextauth].js와 달리 표준적인 Next.js API 핸들러 함수를 작성한다.
이 핸들러 함수가 수행해야 할 로직은 다음과 같다:
- 사용자가 입력한 이전 비밀번호와 새 비밀번호를 추출한다.
- 요청이 인증된 사용자로부터 왔는지 확인하고, 아니라면 거부한다.
- 인증된 사용자의 이메일 주소를 가져온다.
- 데이터베이스에서 사용자를 찾고 이전 비밀번호가 일치하는지 확인한다.
- 일치한다면 새 비밀번호로 업데이트한다.
1. 요청 메서드 확인 (PATCH)
가장 먼저, 들어오는 요청의 메서드가 적절한지 확인해야 한다. 비밀번호 변경은 서버의 리소스(데이터)를 변경하는 작업이므로 POST, PUT, PATCH 중 하나가 적합하다. 여기서는 기존 사용자 리소스를 수정한다는 의미에서 PATCH 메서드를 사용한다. 요청 메서드가 PATCH가 아니라면 함수를 즉시 종료한다. 이는 클라이언트 사이드에서도 반드시 PATCH 요청을 보내야 함을 의미한다.
2. 인증 여부 확인 (getSession)
다음으로 요청이 인증된 사용자로부터 왔는지 확인해야 한다. 이를 위해 getSession 함수를 사용한다. 이 함수는 getServerSideProps에서 사용했던 것과 동일하며, 서버 사이드와 클라이언트 사이드 모두에서 작동한다.
서버 사이드 API 라우트에서 getSession을 사용할 때는 반드시 req (요청 객체)를 포함한 객체를 인자로 전달해야 한다. getSession은 요청 헤더의 쿠키를 살펴보고 세션 토큰을 확인하기 때문이다. 쿠키가 유효하다면 세션 객체를 반환하고, 그렇지 않다면 null 등을 반환한다.
만약 세션이 없다면(인증되지 않은 요청), 401 상태 코드(Unauthorized)와 함께 에러 메시지를 반환하고 로직을 종료한다. 이 블록이 바로 API 라우트를 보호하는 핵심 코드다.
Next Auth v3
강의에서 설명된 Next Auth v3 기준의 pages/api/user/change-password.js 구현은 다음과 같다.
// pages/api/user/change-password.js
import { getSession } from 'next-auth/client'; // v3 import 경로
async function handler(req, res) {
// 1. 요청 메서드 검증
if (req.method !== 'PATCH') {
return;
}
// 2. 세션 확인 (서버 사이드 인증 보호)
// req 객체를 전달하여 쿠키 내의 JWT를 검증하도록 함
const session = await getSession({ req: req });
// API 라우트 보호 - 세션이 없으면 401 에러 반환 및 종료
if (!session) {
res.status(401).json({ message: 'Not authenticated!' });
return;
}
// 이후 비밀번호 변경 로직이 이어짐...
}
export default handler;
코드 동작 원리:
- if (req.method !== 'PATCH'): API가 의도하지 않은 HTTP 메서드로 호출되는 것을 방지한다.
- getSession({ req: req }): 서버 사이드에서 실행되므로, 현재 들어온 HTTP 요청(req)을 인자로 넘겨줘야 한다. Next Auth는 이 요청의 헤더에 있는 쿠키를 파싱하여 JWT 토큰의 유효성을 검사한다.
- if (!session): 유효한 세션이 없다면 즉시 401 응답을 보내어, 인증되지 않은 사용자가 이후의 데이터베이스 로직(비밀번호 변경 등)에 접근하는 것을 원천 차단한다. 이 코드가 API 라우트를 보호하는 로직이다.
Next Auth v4 (최신 버전 적용 예시)
Next Auth v4에서는 서버 사이드 세션 확인 방식이 개선되었다. getSession 대신 getServerSession을 사용하는 것이 권장된다. getServerSession은 불필요한 네트워크 호출 없이 서버 내부에서 직접 세션을 복호화하므로 성능상 이점이 있다. 또한, 설정 파일에 정의된 authOptions가 필요하다.
// pages/api/user/change-password.js
import { getServerSession } from "next-auth/next"; // v4 import 경로
import { authOptions } from "../auth/[...nextauth]"; // NextAuth 설정 가져오기
async function handler(req, res) {
if (req.method !== 'PATCH') {
res.status(405).json({ message: 'Method not allowed' }); // 405 반환이 더 명시적임
return;
}
// v4 방식: getServerSession 사용 (req, res, authOptions 전달)
const session = await getServerSession(req, res, authOptions);
if (!session) {
res.status(401).json({ message: 'Not authenticated!' });
return;
}
// 인증 통과 후 로직...
// const userEmail = session.user.email;
}
export default handler;
v4 주요 변경점:
- Import 경로: next-auth/client가 아닌 next-auth/next에서 가져온다.
- 함수 변경: getSession 대신 getServerSession을 사용한다.
- 인자 전달: req, res와 함께 NextAuth 설정 객체인 authOptions를 함께 전달해야 정확한 세션 검증이 가능하다.
'NextJS > NextAuth' 카테고리의 다른 글
| [NextAuth] Session Provider 사용하기 - 8 (0) | 2025.11.20 |
|---|---|
| [NextAuth] 서버 사이드 페이지 가드 (라우트 보호) 추가하기 - 7 (0) | 2025.11.18 |
| [NextAuth] 클라이언트 사이드 페이지 가드 (라우트 보호) 추가하기 - 6 (0) | 2025.11.18 |
| [NextAuth] 클라이언트 컴포넌트 인증 : 로그인, 로그아웃 -5 (0) | 2025.11.17 |
| [NextAuth] 로그인 API 구현 [...nextauth].js - 4 (0) | 2025.11.16 |