Next.js 인증 (Auth.js v5)
규칙
- 구성은
auth.ts에 중앙 집중화합니다(NextAuth() 내보내기: handlers, auth, signIn, signOut). 제공자 비밀을 분산 배치하지 마십시오.
middleware.ts(엣지 안전 auth 래퍼)에서 경로를 보호하고, 서버 액션/변경 내에서 세션을 다시 확인하십시오 — 미들웨어는 UX일 뿐, 인가가 아닙니다.
- 서버 컴포넌트에서는
await auth()를 통해 세션을 읽습니다. 클라이언트 컴포넌트에서는 <SessionProvider>와 함께 next-auth/react의 useSession()을 사용합니다.
- 비밀(
AUTH_SECRET, 제공자 키)을 NEXT_PUBLIC_ 접두사로 절대 노출하지 마십시오. 부트 시 zod로 환경 변수를 검증하십시오.
- 역할 확인: 모듈 증강(
user.role)을 통해 세션 타입을 확장하고 서버에서 강제 적용합니다.
패턴
import NextAuth from 'next-auth';
import GitHub from 'next-auth/providers/github';
export const { handlers, auth, signIn, signOut } = NextAuth({
providers: [GitHub],
callbacks: {
async session({ session, token }) {
if (session.user) (session.user as { role?: string }).role = token.role as string;
return session;
},
async jwt({ token, user }) {
if (user) token.role = (user as { role?: string }).role ?? 'user';
return token;
},
},
});
export { auth as middleware } from '@/auth';
export const config = { matcher: ['/dashboard/:path*', '/admin/:path*'] };
import { handlers } from '@/auth';
export const { GET, POST } = handlers;
import { auth } from '@/auth';
import { redirect } from 'next/navigation';
export default async function AdminPage() {
const session = await auth();
if (!session?.user) redirect('/login');
if ((session.user as { role?: string }).role !== 'admin')
redirect('/dashboard');
return <AdminView />;
}
import 'next-auth';
declare module 'next-auth' {
interface User { role?: string }
}
체크리스트