https://codesmoothie.tistory.com/81
[NextAuth] 클라이언트 사이드 페이지 가드 (라우트 보호) 추가하기 - 6
로그인하지 않은 사용자는 /profile과 같은 특정 페이지에 접근할 수 없어야 합니다. 만약 해당 페이지에 머무르는 중에 로그아웃을 클릭한다면, 즉시 다른 페이지로 리디렉션되어야 합니다.NextAut
codesmoothie.tistory.com
이전 포스팅에서 클라이언트 사이드 코드를 사용하여 프로필 페이지를 보호했습니다. 로그인하지 않은 사용자가 /profile로 접근하면 /auth 페이지로 리디렉션했습니다. 하지만 이 방식에는 문제가 있습니다. 로그인하지 않은 상태로 /profile 페이지에 직접 URL을 입력하여 접속하면, 잠시 "Loading..." 메시지나 프로필 페이지가 깜빡인 후 로그인 페이지로 리디렉션됩니다. 이 '깜빡임'은 클라이언트 사이드 자바스크립트가 로드되고 실행되어 사용자가 인증되지 않았음을 확인하기까지 걸리는 시간 때문에 발생합니다.
클라이언트 사이드 검증의 한계와 서버 사이드 해결책
이 깜빡임을 클라이언트 사이드 코드만으로는 완전히 제거하기 어렵습니다. 사용자가 페이지를 방문하면, 인증 여부를 판단하는 클라이언트 사이드 코드가 실행되기까지 항상 약간의 지연이 발생하기 때문입니다. 하지만 Next.js는 서버 사이드 코드와 클라이언트 사이드 코드를 함께 사용할 수 있습니다. 이 기능을 활용하면, 서버 사이드에서 사용자가 인증되었는지 미리 확인하고, 인증되지 않았다면 페이지 콘텐츠를 반환하는 대신 즉시 리디렉션을 반환할 수 있습니다.
getServerSideProps 사용하기
이를 위해 pages/profile.js 페이지에 getServerSideProps라는 특별한 함수를 추가해야 합니다.
getStaticProps는 왜 안되는가?
getStaticProps를 생각할 수도 있지만, 이는 잘못된 선택입니다. getStaticProps는 빌드 타임에 실행됩니다. revalidate 옵션을 통해 주기적으로 재생성될 수는 있지만, 기본적으로 모든 요청마다 실행되지 않습니다. 우리의 사례(인증 확인)는 빌드 시점이 아니라, 사용자의 모든 수신 요청(every incoming request) 마다 실행되어야 합니다. 따라서 getStaticProps는 적합하지 않습니다.
getServerSideProps 사용 이유
대신 getServerSideProps를 사용해야 합니다. 이 함수는 페이지에 대한 모든 요청에 대해 서버 측에서 실행됩니다. getServerSideProps는 context 객체를 매개변수로 받으며, 이 객체를 통해 수신되는 요청(request)에 접근할 수 있습니다.
기존 user-profile.js 컴포넌트에서는 next-auth/client의 getSession 함수를 클라이언트 사이드에서 사용하여 세션 정보를 가져왔습니다.
// user-profile.js (v3 이전 코드)
import { getSession } from 'next-auth/client';
import { useEffect, useState } from 'react';
function UserProfile() {
const [session, setSession] = useState(null);
useEffect(() => {
getSession().then((sess) => setSession(sess));
}, []);
if (!session) return <p>Loading...</p>;
return <div>Welcome, {session.user.email}</div>;
}
이 getSession 함수의 중요한 특징은 클라이언트 사이드뿐만 아니라 서버 사이드에서도 작동한다는 것입니다. next-auth/client에서 가져오지만 서버에서도 사용할 수 있습니다. pages/profile.js 파일에 getSession을 임포트하고 getServerSideProps 내에서 호출합니다.
서버 사이드에서 getSession 활용하기 (v3)
// pages/profile.js (v3 환경 예시)
import { getSession } from 'next-auth/client';
import UserProfile from '../components/profile/user-profile';
export async function getServerSideProps(context) {
const session = await getSession({ req: context.req });
if (!session) {
return {
redirect: {
destination: '/auth',
permanent: false,
},
};
}
return {
props: { session },
};
}
export default function ProfilePage({ session }) {
return <UserProfile />;
}
getSession은 전달된 context.req에서 세션 토큰 쿠키 같은 필요한 데이터를 자동으로 추출하고 유효성을 검사합니다.
- 사용자가 인증된 경우: session 변수는 유효한 세션 객체를 가집니다.
- 사용자가 인증되지 않은 경우: session 변수는 null이 됩니다.
getServerSideProps의 리디렉션 로직
이제 session 객체의 유무에 따라 분기 처리를 할 수 있습니다.
인증되지 않은 경우: 리디렉션
session이 null이라면(인증되지 않음), props를 반환하는 대신 redirect 객체를 반환합니다. getServerSideProps는 props 객체 외에도 redirect나 notFound 키를 가진 객체를 반환할 수 있습니다. redirect를 반환하면 Next.js는 해당 페이지를 렌더링하는 대신 사용자를 다른 페이지로 즉시 리디렉션시킵니다.
// pages/profile.js
export async function getServerSideProps(context) {
const session = await getSession({ req: context.req });
if (!session) {
// 세션이 없으면 (로그인 안됨)
return {
redirect: {
destination: '/auth', // 리디렉션할 경로
permanent: false, // 이 리디렉션이 영구적인지 여부
},
};
}
// ...
}
- destination: '/auth': 사용자를 /auth 페이지로 보냅니다.
- permanent: false: 이것은 영구적인 리디렉션이 아님을 명시합니다. 이 리디렉션은 단지 "이번 요청에서 사용자가 로그인하지 않았기 때문"에 발생하는 일시적인 것입니다.
이 로직은 서버에서 실행되므로, 클라이언트는 프로필 페이지의 어떤 내용도 받지 못하고 즉시 /auth 페이지로 이동합니다. '깜빡임' 현상이 완벽하게 사라집니다.
인증된 경우: Props 전달
if (!session) 블록을 통과했다면(인증됨), 정상적으로 props 객체를 반환합니다. 이때 세션 정보를 props로 전달하여 페이지 컴포넌트에서 사용할 수 있습니다.
// pages/profile.js
export async function getServerSideProps(context) {
const session = await getSession({ req: context.req });
if (!session) {
return {
redirect: {
destination: '/auth',
permanent: false,
},
};
}
// 세션이 있으면 페이지가 렌더링되도록 props를 반환
return {
props: { session }, // 세션 정보를 props로 전달
};
}
서버 사이드에서 getServerSession 활용하기 (NextAuth v4 예시)
next-auth v4 이상에서는 getServerSession 함수를 사용하는 것이 권장됩니다. 서버에서 요청, 응답 객체와 authOptions를 전달해 세션을 가져올 수 있습니다.
// pages/profile.js (v4+ 환경 예시)
import { getServerSession } from 'next-auth';
import { authOptions } from './api/auth/[...nextauth]';
import UserProfile from '../components/profile/user-profile';
export async function getServerSideProps(context) {
const session = await getServerSession(context.req, context.res, authOptions);
if (!session) {
return {
redirect: {
destination: '/auth',
permanent: false,
},
};
}
return {
props: { session: JSON.parse(JSON.stringify(session)) },
};
}
export default function ProfilePage({ session }) {
return <UserProfile />;
}
포인트: v4에서는 getServerSession(req, res, authOptions) 사용이 표준이며, props로 전달 시 직렬화(serialization) 처리 필요.
미들웨어
getServerSideProps는 Page Router에서만 지원하며, App Router에서는 지원하지 않는다. NextAuth4 이상에서는 middleware.ts라는 미들웨어를 생성하여 페이지를 보호하는 것이 더 대중적이고 코드 관리가 쉬운편이다. 아래의 두 가지 조건을 충족한다면 미들웨어를 사용을 권장하는 분위기다.
- Strategy: next-auth 설정([...nextauth].ts)에서 session 전략이 jwt여야 합니다. (DB 어댑터를 쓰더라도 middleware는 DB 접근이 제한적이므로 JWT 기반으로 동작합니다.)
- NEXTAUTH_SECRET: 환경 변수(.env)에 NEXTAUTH_SECRET이 반드시 설정되어 있어야 합니다. Middleware가 쿠키(토큰)를 복호화할 때 이 키를 사용합니다.
// [...nextauth].ts 예시
session: {
strategy: "jwt",
},
자세한 내용은 아래 공식 페이지 링크에서 확인하길 바랍니다.
https://next-auth.js.org/tutorials/securing-pages-and-api-routes
Securing pages and API routes | NextAuth.js
You can easily protect client and server side rendered pages and API routes with NextAuth.js.
next-auth.js.org
user-profile.js 컴포넌트 리팩토링 (v3/v4 공통 최종 코드)
pages/profile.js에서 getServerSideProps 또는 getServerSession을 통해 페이지 접근을 제어하므로, 클라이언트 사이드 로딩 상태 관리 코드는 필요 없습니다.
// components/profile/user-profile.js (최종 코드)
import ProfileForm from './profile-form';
import classes from './user-profile.module.css';
function UserProfile() {
async function changePasswordHandler(passwordData) {
// ... 기존 비밀번호 변경 로직
}
return (
<section className={classes.profile}>
<h1>Your User Profile</h1>
<ProfileForm onChangePassword={changePasswordHandler} />
</section>
);
}
export default UserProfile;
최종 동작 확인
- 로그인하지 않은 상태에서 /profile 접속: 페이지 '깜빡임' 없이 즉시 /auth 페이지로 리디렉션됩니다.
- 로그인한 상태에서 /profile 접속: 페이지가 즉시 로드됩니다.
이것이 getServerSideProps를 사용하여 서버 측에서 페이지를 보호하는 더 우아한 방식입니다.
다음 단계로는, 이와 유사한 로직을 /auth 페이지에 적용해 볼 수 있습니다. 즉, 이미 로그인한 사용자가 /auth 페이지에 접근하면 프로필 페이지로 리디렉션시키는 것입니다.
'NextJS > NextAuth' 카테고리의 다른 글
| [NextAuth] API 라우트 보호 - 9 (0) | 2025.11.20 |
|---|---|
| [NextAuth] Session Provider 사용하기 - 8 (0) | 2025.11.20 |
| [NextAuth] 클라이언트 사이드 페이지 가드 (라우트 보호) 추가하기 - 6 (0) | 2025.11.18 |
| [NextAuth] 클라이언트 컴포넌트 인증 : 로그인, 로그아웃 -5 (0) | 2025.11.17 |
| [NextAuth] 로그인 API 구현 [...nextauth].js - 4 (0) | 2025.11.16 |