authentication-best-practices について
Better Auth を使ってセッション管理と認証フローを実装する開発者向けレシピです。クライアント側とサーバー側のセッション取得、ルート保護、サインイン・登録・サインアウトの方法を説明します。
主な機能
- 01クライアント側のセッションフック
- 02サーバー側のセッション取得
- 03認証ルートの保護
- 04サインイン・登録・サインアウト
- 05ユーザーデータの並列取得
活用シーン
- 01クライアントコンポーネントでのセッション確認
- 02未認証のルートリクエストの拒否
- 03セッション検証後のユーザーデータ読み込み
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ andrelandgraf/ fullstackrecipes --skill authentication-best-practicesインストール後、Claude Code で/authentication-best-practicesを入力して読み込まれたか確認します。
詳細
認証のベストプラクティス
Better Auth を使って、セッションの読み取り、ルートの保護、サインイン/サインアップ/サインアウトを行います。
前提条件
まず、次のセットアップ手順を完了してください。
- Better Auth のセットアップ
クライアント側のセッション
クライアントコンポーネントでは、@/lib/auth/client の認証クライアントフックを使用します。
"use client";
import { useSession, signOut } from "@/lib/auth/client";
export function UserMenu() {
const { data: session, isPending } = useSession();
if (isPending) return <div>Loading...</div>;
if (!session) return <a href="/sign-in">Sign In</a>;
return (
<div>
<span>{session.user.name}</span>
<button onClick={() => signOut()}>Sign Out</button>
</div>
);
}
サーバー側のセッション
Server Components と API ルートでは、リクエストの headers を指定して auth.api.getSession を呼び出します。
import { auth } from "@/lib/auth/server";
import { headers } from "next/headers";
const session = await auth.api.getSession({ headers: await headers() });
if (!session) {
return new Response("Unauthorized", { status: 401 });
}
// session.user.id for queries...
ルートの保護
未認証ユーザーは保護されたページからリダイレクトし、認証済みユーザーは認証ページからリダイレクトします。
import { redirect } from "next/navigation";
import { headers } from "next/headers";
import { auth } from "@/lib/auth/server";
export default async function ProtectedPage() {
const session = await auth.api.getSession({ headers: await headers() });
if (!session) redirect("/sign-in");
return <Dashboard user={session.user} />;
}
export default async function SignInPage() {
const session = await auth.api.getSession({ headers: await headers() });
if (session) redirect("/chats");
return <SignIn />;
}
セッションを検証した後、ユーザー固有のデータを並列で取得します。
const [chats, profile] = await Promise.all([
getUserChats(session.user.id),
getUserProfile(session.user.id),
]);
サインイン/サインアップ/サインアウト
import { signIn, signUp, signOut } from "@/lib/auth/client";
await signIn.email({ email, password, callbackURL: "/chats" });
await signIn.social({ provider: "google", callbackURL: "/chats" });
await signUp.email({ email, password, name, callbackURL: "/verify-email" });
await signOut({
fetchOptions: { onSuccess: () => router.push("/") },
});
参考資料
コメント
Markdown 対応