using-authentication について
Fullstack Recipes のスキルで、Better Auth を使ったクライアント側とサーバー側の認証方法を開発者向けに説明します。セッション、ルート保護、サインイン・サインアウト、ユーザーデータ取得を扱います。
主な機能
- 01クライアント側のセッションフック
- 02サーバー側のセッション取得
- 03保護対象ルートのパターン
- 04メールでのサインインと登録
- 05ユーザー別データの取得
活用シーン
- 01ログイン中のユーザーセッションの表示
- 02ページや API ルートの認証必須化
- 03サインインと登録フローの構築
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ andrelandgraf/ fullstackrecipes --skill using-authenticationインストール後、Claude Code で/using-authenticationを入力して読み込まれたか確認します。
詳細
認証の操作
クライアント側とサーバー側の認証には Better Auth を使用します。セッションへのアクセス、保護されたルート、サインイン/サインアウト、ユーザーデータの取得について説明します。
認証の操作の実装
クライアント側とサーバー側の認証には Better Auth を使用します。セッションへのアクセス、保護されたルート、サインイン/サインアウト、ユーザーデータの取得について説明します。
参照:
- リソース:Fullstack Recipes の
using-authentication - URL: https://fullstackrecipes.com/recipes/using-authentication
クライアント側の認証
React コンポーネントで認証クライアントのフックを使用します。
"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 ルートでセッションを取得します。
import { auth } from "@/lib/auth/server";
import { headers } from "next/headers";
// In a Server Component
export default async function Page() {
const session = await auth.api.getSession({
headers: await headers(),
});
if (!session) {
return <div>Not signed in</div>;
}
return <div>Hello, {session.user.name}</div>;
}
// In an API route
export async function POST(request: Request) {
const session = await auth.api.getSession({
headers: await headers(),
});
if (!session) {
return new Response("Unauthorized", { status: 401 });
}
// Use 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} />;
}
認証ページのパターン
認証済みのユーザーが認証ページにアクセスしないようリダイレクトします。
import { redirect } from "next/navigation";
import { headers } from "next/headers";
import { auth } from "@/lib/auth/server";
export default async function SignInPage() {
const session = await auth.api.getSession({
headers: await headers(),
});
if (session) {
redirect("/chats"); // Already signed in
}
return <SignIn />;
}
サインイン
import { signIn } from "@/lib/auth/client";
// Email/password
await signIn.email({
email: "[email protected]",
password: "password",
callbackURL: "/chats",
});
// Social provider
await signIn.social({
provider: "google",
callbackURL: "/chats",
});
サインアップ
import { signUp } from "@/lib/auth/client";
await signUp.email({
email: "[email protected]",
password: "password",
name: "John Doe",
callbackURL: "/verify-email",
});
サインアウト
import { signOut } from "@/lib/auth/client";
await signOut({
fetchOptions: {
onSuccess: () => {
router.push("/");
},
},
});
認証後のユーザーデータの取得
保護されたページでは、セッションを検証した後にユーザー固有のデータを取得します。
export default async function DashboardPage() {
const session = await auth.api.getSession({
headers: await headers(),
});
if (!session) {
redirect("/sign-in");
}
const [chats, profile] = await Promise.all([
getUserChats(session.user.id),
getUserProfile(session.user.id),
]);
return <Dashboard chats={chats} profile={profile} />;
}
参考資料
コメント
Markdown 対応