기본 사용법

Better Auth는 다음과 같은 인증 방법을 기본적으로 지원합니다:

  • 이메일과 비밀번호
  • 소셜 프로바이더 (Google, GitHub, Apple 등)

또한 플러그인을 사용하여 쉽게 확장할 수 있습니다. 예를 들어 사용자명, 매직 링크, 패스키, 이메일 OTP 등이 있습니다.

이메일 & 비밀번호

이메일과 비밀번호 인증을 활성화하려면:

auth.ts
import { betterAuth } from "better-auth"

export const auth = betterAuth({
    emailAndPassword: {    
        enabled: true
    } 
})

회원가입

사용자를 가입시키려면 클라이언트 메서드 signUp.email을 사용자 정보와 함께 호출해야 합니다.

sign-up.ts
import { authClient } from "@/lib/auth-client"; //인증 클라이언트 가져오기

const { data, error } = await authClient.signUp.email({
        email, // 사용자 이메일 주소
        password, // 사용자 비밀번호 -> 기본적으로 최소 8자
        name, // 사용자 표시 이름
        image, // 사용자 이미지 URL (선택사항)
        callbackURL: "/dashboard" // 사용자가 이메일을 인증한 후 리디렉션할 URL (선택사항)
    }, {
        onRequest: (ctx) => {
            //로딩 표시
        },
        onSuccess: (ctx) => {
            //대시보드 또는 로그인 페이지로 리디렉션
        },
        onError: (ctx) => {
            // 오류 메시지 표시
            alert(ctx.error.message);
        },
});

기본적으로 사용자는 회원가입에 성공하면 자동으로 로그인됩니다. 이 동작을 비활성화하려면 autoSignInfalse로 설정할 수 있습니다.

auth.ts
import { betterAuth } from "better-auth"

export const auth = betterAuth({
    emailAndPassword: {
    	enabled: true,
    	autoSignIn: false //기본값은 true
  },
})

로그인

사용자를 로그인시키려면 클라이언트에서 제공하는 signIn.email 함수를 사용할 수 있습니다.

sign-in
const { data, error } = await authClient.signIn.email({
        /**
         * 사용자 이메일
         */
        email,
        /**
         * 사용자 비밀번호
         */
        password,
        /**
         * 사용자가 이메일을 인증한 후 리디렉션할 URL (선택사항)
         */
        callbackURL: "/dashboard",
        /**
         * 브라우저가 닫힌 후에도 사용자 세션을 기억합니다.
         * @default true
         */
        rememberMe: false
}, {
    //콜백
})

항상 클라이언트 측에서 클라이언트 메서드를 호출하세요. 서버에서 호출하지 마세요.

서버 측 인증

서버에서 사용자를 인증하려면 auth.api 메서드를 사용할 수 있습니다.

server.ts
import { auth } from "./auth"; // Better Auth 서버 인스턴스 경로

const response = await auth.api.signInEmail({
    body: {
        email,
        password
    },
    asResponse: true // 데이터 대신 응답 객체 반환
});

서버가 응답 객체를 반환할 수 없는 경우, 쿠키를 수동으로 파싱하고 설정해야 합니다. 하지만 Next.js와 같은 프레임워크의 경우 이를 자동으로 처리하는 플러그인을 제공합니다.

소셜 로그인

Better Auth는 Google, GitHub, Apple, Discord 등 여러 소셜 프로바이더를 지원합니다. 소셜 프로바이더를 사용하려면 auth 객체의 socialProviders 옵션에서 필요한 프로바이더를 설정해야 합니다.

auth.ts
import { betterAuth } from "better-auth";

export const auth = betterAuth({
    socialProviders: { 
        github: { 
            clientId: process.env.GITHUB_CLIENT_ID!, 
            clientSecret: process.env.GITHUB_CLIENT_SECRET!, 
        } 
    }, 
})

소셜 프로바이더로 로그인

소셜 프로바이더를 사용하여 로그인하려면 signIn.social을 호출해야 합니다. 다음 속성을 가진 객체를 받습니다:

sign-in.ts
import { authClient } from "@/lib/auth-client"; //인증 클라이언트 가져오기

await authClient.signIn.social({
    /**
     * 소셜 프로바이더 ID
     * @example "github", "google", "apple"
     */
    provider: "github",
    /**
     * 프로바이더로 사용자 인증 후 리디렉션할 URL
     * @default "/"
     */
    callbackURL: "/dashboard",
    /**
     * 로그인 과정에서 오류가 발생할 경우 리디렉션할 URL
     */
    errorCallbackURL: "/error",
    /**
     * 사용자가 새로 가입한 경우 리디렉션할 URL
     */
    newUserCallbackURL: "/welcome",
    /**
     * 프로바이더로의 자동 리디렉션을 비활성화합니다.
     * @default false
     */
    disableRedirect: true,
});

사용자를 프로바이더 사이트로 리디렉션하는 대신 소셜 프로바이더의 idToken 또는 accessToken을 사용하여 인증할 수도 있습니다. 자세한 내용은 소셜 프로바이더 문서를 참조하세요.

로그아웃

사용자를 로그아웃시키려면 클라이언트에서 제공하는 signOut 함수를 사용할 수 있습니다.

user-card.tsx
await authClient.signOut();

성공 시 리디렉션하려면 fetchOptions를 전달할 수 있습니다.

user-card.tsx
await authClient.signOut({
  fetchOptions: {
    onSuccess: () => {
      router.push("/login"); // 로그인 페이지로 리디렉션
    },
  },
});

세션

사용자가 로그인하면 사용자 세션에 액세스하고 싶을 것입니다. Better Auth를 사용하면 서버와 클라이언트 측 모두에서 세션 데이터에 쉽게 액세스할 수 있습니다.

클라이언트 측

useSession 사용

Better Auth는 클라이언트 측에서 세션 데이터에 쉽게 액세스할 수 있는 useSession 훅을 제공합니다. 이 훅은 nanostore를 사용하여 구현되었으며 지원되는 각 프레임워크와 바닐라 클라이언트를 지원하므로 세션의 모든 변경 사항(예: 로그아웃)이 UI에 즉시 반영됩니다.

user.tsx
import { authClient } from "@/lib/auth-client" // 인증 클라이언트 가져오기

export function User(){

    const { 
        data: session, 
        isPending, //로딩 상태
        error, //오류 객체
        refetch //세션 다시 가져오기
    } = authClient.useSession() 

    return (
        //...
    )
}
index.vue
<script setup lang="ts">
import { authClient } from "~/lib/auth-client"

const session = authClient.useSession() 
</script>

<template>
    <div>
        <div>
            <pre>{{ session.data }}</pre>
            <button v-if="session.data" @click="authClient.signOut()">
                로그아웃
            </button>
        </div>
    </div>
</template>
user.svelte
<script lang="ts">
import { authClient } from "$lib/auth-client"; 

const session = authClient.useSession(); 
</script>
<p>
    {$session.data?.user.email}
</p>
user.svelte
import { authClient } from "~/lib/auth-client"; //인증 클라이언트 가져오기

authClient.useSession.subscribe((value)=>{
    //세션으로 무언가 수행 //
})
user.tsx
import { authClient } from "~/lib/auth-client"; 

export default function Home() {
    const session = authClient.useSession() 
    return (
        <pre>{JSON.stringify(session(), null, 2)}</pre>
    );
}

getSession 사용

훅을 사용하지 않으려면 클라이언트에서 제공하는 getSession 메서드를 사용할 수 있습니다.

user.tsx
import { authClient } from "@/lib/auth-client" // 인증 클라이언트 가져오기

const { data: session, error } = await authClient.getSession()

TanStack Query와 같은 클라이언트 측 데이터 페칭 라이브러리와 함께 사용할 수도 있습니다.

서버 측

서버는 세션 데이터에 액세스하는 데 사용할 수 있는 session 객체를 제공합니다. getSession 메서드에 요청 헤더 객체를 전달해야 합니다.

예제: 인기 있는 프레임워크 사용

server.ts
import { auth } from "./auth"; // Better Auth 서버 인스턴스 경로
import { headers } from "next/headers";

const session = await auth.api.getSession({
    headers: await headers() // 헤더 객체를 전달해야 합니다.
})
route.ts
import { auth } from "lib/auth"; // Better Auth 서버 인스턴스 경로

export async function loader({ request }: LoaderFunctionArgs) {
    const session = await auth.api.getSession({
        headers: request.headers
    })

    return json({ session })
}
index.astro
---
import { auth } from "./auth";

const session = await auth.api.getSession({
    headers: Astro.request.headers,
});
---
<!-- Astro 템플릿 -->
+page.ts
import { auth } from "./auth";

export async function load({ request }) {
    const session = await auth.api.getSession({
        headers: request.headers
    })
    return {
        props: {
            session
        }
    }
}
index.ts
import { auth } from "./auth";

const app = new Hono();

app.get("/path", async (c) => {
    const session = await auth.api.getSession({
        headers: c.req.raw.headers
    })
});
server/session.ts
import { auth } from "~/utils/auth";

export default defineEventHandler((event) => {
    const session = await auth.api.getSession({
        headers: event.headers,
    })
});
app/routes/api/index.ts
import { auth } from "./auth";
import { createAPIFileRoute } from "@tanstack/start/api";

export const APIRoute = createAPIFileRoute("/api/$")({
    GET: async ({ request }) => {
        const session = await auth.api.getSession({
            headers: request.headers
        })
    },
});

자세한 내용은 세션 관리 문서를 확인하세요.

플러그인 사용

Better Auth의 고유한 기능 중 하나는 플러그인 생태계입니다. 이를 통해 적은 코드로 복잡한 인증 관련 기능을 추가할 수 있습니다.

다음은 2단계 인증 플러그인을 사용하여 2단계 인증을 추가하는 예제입니다.

서버 구성

플러그인을 추가하려면 플러그인을 가져와서 인증 인스턴스의 plugins 옵션에 전달해야 합니다. 예를 들어 2단계 인증을 추가하려면 다음 코드를 사용할 수 있습니다:

auth.ts
import { betterAuth } from "better-auth"
import { twoFactor } from "better-auth/plugins"

export const auth = betterAuth({
    //...나머지 옵션
    plugins: [ 
        twoFactor() 
    ] 
})

이제 2단계 인증 관련 라우트와 메서드가 서버에서 사용 가능합니다.

데이터베이스 마이그레이션

플러그인을 추가한 후 데이터베이스에 필요한 테이블을 추가해야 합니다. migrate 명령을 실행하거나 generate 명령을 사용하여 스키마를 생성하고 수동으로 마이그레이션을 처리할 수 있습니다.

스키마 생성:

terminal
npx @better-auth/cli generate

migrate 명령 사용:

terminal
npx @better-auth/cli migrate

스키마를 수동으로 추가하려면 2단계 인증 플러그인 문서에서 필요한 스키마를 확인할 수 있습니다.

클라이언트 구성

서버 작업이 완료되면 클라이언트에 플러그인을 추가해야 합니다. 이를 위해 플러그인을 가져와서 인증 클라이언트의 plugins 옵션에 전달해야 합니다. 예를 들어 2단계 인증을 추가하려면 다음 코드를 사용할 수 있습니다:

auth-client.ts
import { createAuthClient } from "better-auth/client";
import { twoFactorClient } from "better-auth/client/plugins"; 

const authClient = createAuthClient({
    plugins: [ 
        twoFactorClient({ 
            twoFactorPage: "/two-factor" // 사용자가 2단계 인증을 확인해야 할 때 리디렉션할 페이지
        }) 
    ] 
})

이제 2단계 인증 관련 메서드가 클라이언트에서 사용 가능합니다.

profile.ts
import { authClient } from "./auth-client"

const enableTwoFactor = async() => {
    const data = await authClient.twoFactor.enable({
        password // 사용자 비밀번호가 필요합니다
    }) // 2단계 인증을 활성화합니다
}

const disableTwoFactor = async() => {
    const data = await authClient.twoFactor.disable({
        password // 사용자 비밀번호가 필요합니다
    }) // 2단계 인증을 비활성화합니다
}

const signInWith2Factor = async() => {
    const data = await authClient.signIn.email({
        //...
    })
    //사용자가 2단계 인증을 활성화한 경우 2단계 인증 페이지로 리디렉션됩니다
}

const verifyTOTP = async() => {
    const data = await authClient.twoFactor.verifyTOTP({
        code: "123456", // 사용자가 입력한 코드
        /**
         * 기기를 신뢰하는 경우 사용자는
         * 동일한 기기에서 다시 2단계 인증을 통과할 필요가 없습니다
         */
        trustDevice: true
    })
}

다음 단계: 2단계 인증 플러그인 문서를 참조하세요.

On this page