Next.js 통합
Better Auth는 Next.js와 쉽게 통합할 수 있습니다. 시작하기 전에 Better Auth 인스턴스가 구성되어 있는지 확인하세요. 아직 설정하지 않았다면 설치 가이드를 확인하세요.
API 라우트 생성
핸들러를 API 라우트에 마운트해야 합니다. /api/auth/[...all] 디렉터리 내에 라우트 파일을 생성하고 다음 코드를 추가하세요:
import { auth } from "@/lib/auth";
import { toNextJsHandler } from "better-auth/next-js";
export const { GET, POST } = toNextJsHandler(auth.handler);Better Auth 설정에서 경로를 변경할 수 있지만 /api/auth/[...all]로 유지하는 것을 권장합니다
pages 라우트의 경우 toNextJsHandler 대신 toNodeHandler를 사용하고 config 객체에서 bodyParser를 false로 설정해야 합니다. 다음은 예시입니다:
import { toNodeHandler } from "better-auth/node"
import { auth } from "@/lib/auth"
// 바디 파싱 비활성화, 수동으로 파싱할 것입니다
export const config = { api: { bodyParser: false } }
export default toNodeHandler(auth.handler)클라이언트 생성
클라이언트 인스턴스를 생성합니다. 파일 이름은 원하는 대로 지정할 수 있습니다. 여기서는 lib/ 디렉터리 내에 client.ts 파일을 생성합니다.
import { createAuthClient } from "better-auth/react" // better-auth/react에서 import해야 합니다
export const authClient = createAuthClient({
// 클라이언트 설정을 여기에 전달할 수 있습니다
})클라이언트를 생성한 후에는 회원가입, 로그인 및 기타 작업을 수행할 수 있습니다. 일부 작업은 반응형입니다. 클라이언트는 nano-store를 사용하여 상태를 저장하고 상태가 변경될 때 컴포넌트를 다시 렌더링합니다.
클라이언트는 또한 better-fetch를 사용하여 요청을 만듭니다. 클라이언트에 fetch 설정을 전달할 수 있습니다.
RSC 및 서버 액션
auth 인스턴스에서 내보낸 api 객체에는 서버에서 수행할 수 있는 모든 작업이 포함되어 있습니다. Better Auth 내에서 만들어진 모든 엔드포인트는 함수로 호출할 수 있습니다. 플러그인 엔드포인트도 포함됩니다.
예제: 서버 액션에서 세션 가져오기
import { auth } from "@/lib/auth"
import { headers } from "next/headers"
const someAuthenticatedAction = async () => {
"use server";
const session = await auth.api.getSession({
headers: await headers()
})
};예제: RSC에서 세션 가져오기
import { auth } from "@/lib/auth"
import { headers } from "next/headers"
export async function ServerComponent() {
const session = await auth.api.getSession({
headers: await headers()
})
if(!session) {
return <div>인증되지 않음</div>
}
return (
<div>
<h1>환영합니다 {session.user.name}님</h1>
</div>
)
}서버 액션 쿠키
서버 액션에서 signInEmail이나 signUpEmail과 같이 쿠키를 설정해야 하는 함수를 호출할 때 쿠키가 설정되지 않습니다. 서버 액션은 쿠키를 설정하기 위해 Next.js의 cookies 헬퍼를 사용해야 하기 때문입니다.
이를 간단하게 하기 위해 nextCookies 플러그인을 사용할 수 있습니다. 이 플러그인은 응답에 Set-Cookie 헤더가 있을 때마다 자동으로 쿠키를 설정합니다.
import { betterAuth } from "better-auth";
import { nextCookies } from "better-auth/next-js";
export const auth = betterAuth({
//...설정
plugins: [nextCookies()] // 배열의 마지막 플러그인으로 추가해야 합니다
})이제 쿠키를 설정하는 함수를 호출하면 자동으로 설정됩니다.
"use server";
import { auth } from "@/lib/auth"
const signIn = async () => {
await auth.api.signInEmail({
body: {
email: "user@email.com",
password: "password",
}
})
}미들웨어
Next.js 미들웨어에서는 API 호출이나 데이터베이스 호출로 요청을 차단하지 않도록 세션 쿠키의 존재 여부만 확인하여 리디렉션을 처리하는 것이 좋습니다.
이를 위해 Better Auth의 getSessionCookie 헬퍼를 사용할 수 있습니다:
getSessionCookie() 함수는 auth.ts에 지정된 인증 설정을 자동으로 참조하지 않습니다. 따라서 쿠키 이름이나 접두사를 사용자 정의한 경우 getSessionCookie()의 설정이 auth.ts에 정의된 설정과 일치하는지 확인해야 합니다.
import { NextRequest, NextResponse } from "next/server";
import { getSessionCookie } from "better-auth/cookies";
export async function middleware(request: NextRequest) {
const sessionCookie = getSessionCookie(request);
// 이것은 안전하지 않습니다!
// 사용자를 낙관적으로 리디렉션하기 위한 권장 접근 방식입니다
// 각 페이지/라우트에서 인증 확인을 처리하는 것을 권장합니다
if (!sessionCookie) {
return NextResponse.redirect(new URL("/", request.url));
}
return NextResponse.next();
}
export const config = {
matcher: ["/dashboard"], // 미들웨어가 적용될 라우트 지정
};보안 경고: getSessionCookie 함수는 세션 쿠키의 존재 여부만 확인하며 유효성을 검증하지 않습니다. 보안을 위해 이 확인만 의존하는 것은 위험합니다. 누구나 수동으로 쿠키를 생성하여 우회할 수 있기 때문입니다. 보호된 작업이나 페이지에 대해서는 항상 서버에서 세션을 검증해야 합니다.
커스텀 쿠키 이름이나 접두사가 있는 경우 getSessionCookie 함수에 전달할 수 있습니다.
const sessionCookie = getSessionCookie(request, {
cookieName: "my_session_cookie",
cookiePrefix: "my_prefix"
});또는 getCookieCache 헬퍼를 사용하여 쿠키 캐시에서 세션 객체를 가져올 수 있습니다.
import { getCookieCache } from "better-auth/cookies";
export async function middleware(request: NextRequest) {
const session = await getCookieCache(request);
if (!session) {
return NextResponse.redirect(new URL("/sign-in", request.url));
}
return NextResponse.next();
}각 페이지/라우트에서 인증 확인을 처리하는 방법
이 예제에서는 서버 컴포넌트 내에서 auth.api.getSession 함수를 사용하여 세션 객체를 가져온 다음 세션이 유효한지 확인합니다. 유효하지 않으면 사용자를 로그인 페이지로 리디렉션합니다.
import { auth } from "@/lib/auth";
import { headers } from "next/headers";
import { redirect } from "next/navigation";
export default async function DashboardPage() {
const session = await auth.api.getSession({
headers: await headers()
})
if(!session) {
redirect("/sign-in")
}
return (
<div>
<h1>환영합니다 {session.user.name}님</h1>
</div>
)
}Next.js 릴리스 15.1.7 이하 버전
전체 세션 객체가 필요한 경우 /get-session API 라우트에서 가져와야 합니다. Next.js 미들웨어는 Node.js API를 직접 실행할 수 없으므로 HTTP 요청을 해야 합니다.
이 예제는 better-fetch를 사용하지만 어떤 fetch 라이브러리든 사용할 수 있습니다.
import { betterFetch } from "@better-fetch/fetch";
import type { auth } from "@/lib/auth";
import { NextRequest, NextResponse } from "next/server";
type Session = typeof auth.$Infer.Session;
export async function middleware(request: NextRequest) {
const { data: session } = await betterFetch<Session>("/api/auth/get-session", {
baseURL: request.nextUrl.origin,
headers: {
cookie: request.headers.get("cookie") || "", // 요청에서 쿠키 전달
},
});
if (!session) {
return NextResponse.redirect(new URL("/sign-in", request.url));
}
return NextResponse.next();
}
export const config = {
matcher: ["/dashboard"], // 특정 라우트에 미들웨어 적용
};Next.js 릴리스 15.2.0 이상 버전
15.2.0 버전부터 Next.js는 미들웨어에서 Node.js 런타임을 사용할 수 있습니다. 즉, 미들웨어에서 auth.api 객체를 직접 사용할 수 있습니다.
런타임 설정에 대한 자세한 내용과 활성화 방법은 Next.js 문서를 참조하세요. 새로운 런타임을 사용할 때는 주의하세요. 실험적 기능이므로 중대한 변경사항이 있을 수 있습니다.
import { NextRequest, NextResponse } from "next/server";
import { headers } from "next/headers";
import { auth } from "@/lib/auth";
export async function middleware(request: NextRequest) {
const session = await auth.api.getSession({
headers: await headers()
})
if(!session) {
return NextResponse.redirect(new URL("/sign-in", request.url));
}
return NextResponse.next();
}
export const config = {
runtime: "nodejs",
matcher: ["/dashboard"], // 특정 라우트에 미들웨어 적용
};