Better Auth で Web アプリに認証機能を追加する方法

認証は、ほぼすべての Web アプリケーションにおいて重要な機能です。SaaS 製品、個人プロジェクト、社内ツールのいずれを構築する場合でも、ユーザーのサインイン機能が必要になることがほとんどです。
しかし、認証をゼロから実装するのは簡単ではありません。パスワードの安全なハッシュ化、セッション管理、OAuth フロー、トークンの更新など、問題が発生しやすい要素が数多くあります。認証は重要ですが、アプリを差別化する機能ではありません。他の部分に時間を使いたいと思うのが自然です。
そこで Better Auth の出番です。
Better Auth は、Web アプリケーションの認証を簡素化するために設計された、TypeScript ファーストの認証ライブラリです。
柔軟性、移植性、開発者に優しい API を重視しています:
- フレームワーク非依存: SvelteKit、Next.js、Nuxt、Express などのフレームワークと統合可能
- ソーシャルプロバイダー内蔵: Google、GitHub、Discord、Twitter などの一般的な OAuth プロバイダーに対応
- シンプルな API: 一般的な認証シナリオに対して、最小限の設定で利用可能
- ベンダーロックインなし: データベースに依存せず、さまざまなプラットフォームにデプロイ可能
このガイドでは、Better Auth を SvelteKit に統合する手順を説明します。最終的には、ソーシャルログインに対応した認証システムが完成します。
SvelteKit との統合
1. インストールとセットアップ
まず、新しい SvelteKit プロジェクトを作成します(既存のプロジェクトを使用することも可能です):
npx sv create my-app
cd my-appBetter Auth をインストールします:
npm install better-auth次に、環境変数を設定します。プロジェクトのルートディレクトリに .env ファイルを作成します:
# Better Auth Secret Key
BETTER_AUTH_SECRET=your-better-auth-secret
# GitHub OAuth
GITHUB_CLIENT_ID=your-github-client-id
GITHUB_CLIENT_SECRET=your-github-client-secret
# Google OAuth
GOOGLE_CLIENT_ID=your-google-client-id
GOOGLE_CLIENT_SECRET=your-google-client-secretBETTER_AUTH_SECRET を生成するには、ターミナルで以下のコマンドを実行します:
openssl rand -base64 32OAuth 認証情報の取得方法:
- GitHub: GitHub Developer Settings にアクセスし、新しい OAuth App を作成
- Google: Google Cloud Console にアクセスし、プロジェクトを作成して OAuth 2.0 認証情報を設定
コールバック URL を http://localhost:5173/api/auth/callback/github (Google の場合は /google )に設定します。
2. サーバー設定
サーバー側で auth インスタンスを作成します。ここでプロバイダーと設定を定義します。
src/lib/server/auth.ts を作成します:
import { betterAuth } from 'better-auth';
import { env } from '$env/dynamic/private';
export const auth = betterAuth({
secret: env.BETTER_AUTH_SECRET,
socialProviders: {
github: {
clientId: env.GITHUB_CLIENT_ID as string,
clientSecret: env.GITHUB_CLIENT_SECRET as string
},
google: {
clientId: env.GOOGLE_CLIENT_ID as string,
clientSecret: env.GOOGLE_CLIENT_SECRET as string
}
}
});次に API ルートハンドラーを作成します。Better Auth はキャッチオールルートを使用して、認証関連のすべてのリクエストを処理します。
src/routes/api/auth/[...all]/+server.ts を作成します:
import { auth } from '$lib/server/auth';
import type { RequestHandler } from './$types';
export const GET: RequestHandler = async ({ request }) => {
return auth.handler(request);
};
export const POST: RequestHandler = async ({ request }) => {
return auth.handler(request);
};サーバー側の設定は以上です。Better Auth は /api/auth/* ルートを自動的に処理します。
3. クライアント設定
Svelte コンポーネントで使用する auth クライアントを作成します。
src/lib/auth-client.ts を作成します:
import { createAuthClient } from 'better-auth/svelte';
export const authClient = createAuthClient();クライアントは認証エンドポイントを自動的に検出します。これで、アプリ内のどこでも authClient を使用してサインインやサインアウトを実行できます。
4. ソーシャルログインの実装
まず、 src/hooks.server.ts を作成して、各リクエストでユーザーセッションを取得します:
import { auth } from '$lib/server/auth';
import type { Handle } from '@sveltejs/kit';
export const handle: Handle = async ({ event, resolve }) => {
const session = await auth.api.getSession({
headers: event.request.headers
});
event.locals.session = session;
return resolve(event);
};locals の型定義を追加します。 src/app.d.ts を更新します:
import type { auth } from '$lib/server/auth';
declare global {
namespace App {
interface Locals {
session: typeof auth.$Infer.Session | null;
}
}
}
export {};次に、セッションデータをすべてのページに渡す layout server load 関数を作成します。
src/routes/+layout.server.ts を作成します:
import type { LayoutServerLoad } from './$types';
export const load: LayoutServerLoad = async ({ locals }) => {
return {
session: locals.session
};
};ログインページを作成します。 src/routes/login/+page.svelte を作成します:
<script lang="ts">
import { authClient } from '$lib/auth-client';
const signInWithGitHub = async () => {
await authClient.signIn.social({
provider: 'github',
callbackURL: '/'
});
};
const signInWithGoogle = async () => {
await authClient.signIn.social({
provider: 'google',
callbackURL: '/'
});
};
</script>
<div class="login-container">
<h1>Sign In</h1>
<button onclick={signInWithGitHub}>Continue with GitHub</button>
<button onclick={signInWithGoogle}>Continue with Google</button>
</div>ユーザー情報の表示とサインアウト処理のために、layout コンポーネントを更新します。 src/routes/+layout.svelte を編集します:
<script lang="ts">
import { authClient } from '$lib/auth-client';
let { data, children } = $props();
const signOut = async () => {
await authClient.signOut();
};
</script>
<header>
{#if data.session}
<p>Welcome, {data.session.user.name}!</p>
<button onclick={signOut}>Sign Out</button>
{:else}
<a href="/login">Sign In</a>
{/if}
</header>
<main>
{@render children()}
</main>この方法は SSR に対応しています。セッションデータはページ読み込み時にすぐに利用可能で、未認証コンテンツのちらつきが発生しません。
5. ルート保護
特定のルートを保護するには、 src/hooks.server.ts を更新して、ページのレンダリング前に認証を確認します:
import { auth } from '$lib/server/auth';
import { redirect, type Handle } from '@sveltejs/kit';
const protectedRoutes = ['/dashboard', '/settings', '/profile'];
export const handle: Handle = async ({ event, resolve }) => {
const session = await auth.api.getSession({
headers: event.request.headers
});
event.locals.session = session;
const isProtected = protectedRoutes.some((route) => event.route.id?.startsWith(route));
if (isProtected && !session) {
throw redirect(303, '/login');
}
return resolve(event);
};これで、 /dashboard 、 /settings 、 /profile で始まるルートは、未認証ユーザーをログインページにリダイレクトします。
6. データベース(オプション)
デフォルトでは、Better Auth はセッションをメモリに保存します。開発環境ではこれで問題ありませんが、本番環境ではサーバー再起動後もユーザーデータを保持するためにデータベースが必要です。
Better Auth は Prisma、Drizzle、MongoDB など、複数のデータベースアダプターをサポートしています。
Prisma を使用した例を示します:
import { betterAuth } from 'better-auth';
import { prismaAdapter } from 'better-auth/adapters/prisma';
import { PrismaClient } from '@prisma/client';
const prisma = new PrismaClient();
export const auth = betterAuth({
database: prismaAdapter(prisma, {
provider: 'sqlite', // or mysql, postgresql
}),
socialProviders: {
// ... your providers
}
});データベース設定の詳細については、Better Auth データベースドキュメント を参照してください。
クイックスタートテンプレート
すぐに始めたい場合は、すべて設定済みの SvelteKit + Better Auth テンプレートを用意しています:
- GitHub、Google、Discord、Slack、Vercel OAuth 設定済み
- SSR 対応のセッション管理
- ルート保護のサンプル
- 環境変数テンプレート
まとめ
認証の追加は複雑である必要はありません。Better Auth と SvelteKit を使えば、1 時間以内に完全なソーシャルログインシステムを構築できます。
このガイドで説明した内容:
- SvelteKit プロジェクトでの Better Auth の設定
- Google と GitHub OAuth プロバイダーの設定
- サインイン/サインアウト機能の構築
- server hooks によるルート保護
- 本番環境向けのデータベース設定(オプション)
さらに速く始めたい場合は、テンプレートを使ってワンクリックでデプロイできます。