認証OSS比較:Auth.js vs Lucia vs BetterAuth でNext.jsに認証を実装する
オープンソースラボ編集部 ・ 2026年6月13日
認証OSS比較:Auth.js vs Lucia vs BetterAuth でNext.jsに認証を実装する
Clerkは便利ですが月$25〜のコストがかかります。Auth.js(NextAuth v5)・Lucia・BetterAuthはNext.jsにOAuth・メール/パスワード・パスワードレス(マジックリンク)認証をOSSで実装できます。Supabase Authとの使い分けや、セッション管理・ロールベースアクセス制御(RBAC)の実装方法も解説します。
認証ライブラリが必要な場面
- OAuth統合: Google・GitHub・Microsoft・LINEなど複数プロバイダーのソーシャルログインを実装したい
- セッション管理: JWTとセッションCookieのどちらかを選んで安全にユーザー状態を管理したい
- パスワードレス認証: メールのマジックリンクやWebAuthn(パスキー)でパスワードを廃止したい
- RBAC: ユーザーの役割(admin・editor・viewer)によってアクセス可能なページを制限したい
- 自社DB管理: ユーザーデータを自社のPostgreSQLに保存したい(Clerk・Auth0はSaaS)
主要ツールの概要
Auth.js(NextAuth v5)
Next.jsとの統合が最も充実したOAuth認証ライブラリです。GitHubスター24k+で、最も広く使われているNext.js認証ソリューションです。v5(旧NextAuth→Auth.js)でApp Router完全対応になりました。
// auth.ts - Auth.jsの設定
import NextAuth from "next-auth";
import GitHub from "next-auth/providers/github";
import Google from "next-auth/providers/google";
import Credentials from "next-auth/providers/credentials";
import { DrizzleAdapter } from "@auth/drizzle-adapter";
import { db } from "@/lib/db";
export const { handlers, auth, signIn, signOut } = NextAuth({
// Supabase PostgreSQLをアダプターとして使う
adapter: DrizzleAdapter(db),
providers: [
GitHub({
clientId: process.env.AUTH_GITHUB_ID!,
clientSecret: process.env.AUTH_GITHUB_SECRET!,
}),
Google({
clientId: process.env.AUTH_GOOGLE_ID!,
clientSecret: process.env.AUTH_GOOGLE_SECRET!,
}),
// メール/パスワード認証
Credentials({
credentials: {
email: { label: "Email", type: "email" },
password: { label: "Password", type: "password" },
},
authorize: async (credentials) => {
const { email, password } = credentials as { email: string; password: string };
const user = await db.query.users.findFirst({
where: (u, { eq }) => eq(u.email, email),
});
if (!user) return null;
const valid = await bcrypt.compare(password, user.passwordHash);
if (!valid) return null;
return { id: user.id, email: user.email, role: user.role };
},
}),
],
callbacks: {
// JWTにロールを追加
jwt: async ({ token, user }) => {
if (user) token.role = (user as any).role;
return token;
},
session: async ({ session, token }) => {
if (session.user) session.user.role = token.role as string;
return session;
},
},
pages: {
signIn: "/login",
error: "/login",
},
});
// app/api/auth/[...nextauth]/route.ts
import { handlers } from "@/auth";
export const { GET, POST } = handlers;
// middleware.ts - 認証が必要なルートを保護
import { auth } from "@/auth";
import { NextResponse } from "next/server";
export default auth((req) => {
const isLoggedIn = !!req.auth;
const isProtected = req.nextUrl.pathname.startsWith("/dashboard");
if (isProtected && !isLoggedIn) {
return NextResponse.redirect(new URL("/login", req.url));
}
});
export const config = {
matcher: ["/((?!api|_next/static|_next/image|favicon.ico).*)"],
};
// Server ComponentからセッションをGETする
import { auth } from "@/auth";
export default async function Dashboard() {
const session = await auth();
if (!session?.user) {
redirect("/login");
}
return (
<div>
<h1>こんにちは、{session.user.name}さん</h1>
<p>メール: {session.user.email}</p>
<p>ロール: {session.user.role}</p>
</div>
);
}
Lucia
軽量で型安全なセッション管理ライブラリです。GitHubスター8k+。Auth.jsより低レベルで、セッションとユーザーの管理だけに集中した設計です。OAuth・パスワード・パスキーなどの認証メカニズムは自分で組み合わせます。
// lib/lucia.ts - Luciaの設定
import { Lucia } from "lucia";
import { DrizzlePostgreSQLAdapter } from "@lucia-auth/adapter-drizzle";
import { db, sessions, users } from "@/lib/db";
import { cookies } from "next/headers";
import { cache } from "react";
const adapter = new DrizzlePostgreSQLAdapter(db, sessions, users);
export const lucia = new Lucia(adapter, {
sessionCookie: {
attributes: {
secure: process.env.NODE_ENV === "production",
},
},
getUserAttributes: (attributes) => ({
email: attributes.email,
role: attributes.role,
name: attributes.name,
}),
});
// 現在のユーザーを取得するヘルパー(キャッシュあり)
export const validateRequest = cache(async () => {
const sessionId = cookies().get(lucia.sessionCookieName)?.value ?? null;
if (!sessionId) return { user: null, session: null };
const { user, session } = await lucia.validateSession(sessionId);
if (session?.fresh) {
const sessionCookie = lucia.createSessionCookie(session.id);
cookies().set(sessionCookie.name, sessionCookie.value, sessionCookie.attributes);
}
if (!session) {
const sessionCookie = lucia.createBlankSessionCookie();
cookies().set(sessionCookie.name, sessionCookie.value, sessionCookie.attributes);
}
return { user, session };
});
// app/api/login/route.ts - メール/パスワードログイン
import { lucia } from "@/lib/lucia";
import { db } from "@/lib/db";
import { cookies } from "next/headers";
export async function POST(req: Request) {
const { email, password } = await req.json();
const user = await db.query.users.findFirst({
where: (u, { eq }) => eq(u.email, email),
});
if (!user || !await bcrypt.compare(password, user.passwordHash)) {
return Response.json({ error: "Invalid credentials" }, { status: 401 });
}
// セッションを作成
const session = await lucia.createSession(user.id, {});
const sessionCookie = lucia.createSessionCookie(session.id);
cookies().set(sessionCookie.name, sessionCookie.value, sessionCookie.attributes);
return Response.json({ success: true });
}
BetterAuth
Next.js・Nuxt・SvelteKit等のフレームワークに対応した最新の認証ライブラリです。GitHubスター6k+で急成長中。Auth.jsより型安全で、プラグインアーキテクチャによる拡張性が高いです。
// lib/auth.ts - BetterAuthの設定
import { betterAuth } from "better-auth";
import { drizzleAdapter } from "better-auth/adapters/drizzle";
import { nextCookies } from "better-auth/next-js";
import { twoFactor, magicLink, passkey } from "better-auth/plugins";
import { db } from "./db";
export const auth = betterAuth({
database: drizzleAdapter(db, {
provider: "pg",
}),
plugins: [
// 二段階認証(TOTP)
twoFactor(),
// マジックリンク(パスワードレス)
magicLink({
sendMagicLink: async ({ email, url }) => {
await resend.emails.send({
from: "auth@yoursite.com",
to: email,
subject: "ログインリンク",
html: `<a href="${url}">こちらからログイン</a>`,
});
},
}),
// パスキー(WebAuthn)
passkey(),
// Cookieの設定(Next.js App Router用)
nextCookies(),
],
emailAndPassword: {
enabled: true,
requireEmailVerification: true,
sendResetPassword: async ({ user, url }) => {
await resend.emails.send({
from: "auth@yoursite.com",
to: user.email,
subject: "パスワードリセット",
html: `<a href="${url}">パスワードをリセット</a>`,
});
},
},
socialProviders: {
github: {
clientId: process.env.GITHUB_CLIENT_ID!,
clientSecret: process.env.GITHUB_CLIENT_SECRET!,
},
google: {
clientId: process.env.GOOGLE_CLIENT_ID!,
clientSecret: process.env.GOOGLE_CLIENT_SECRET!,
},
},
});
export type Session = typeof auth.$Infer.Session;
export type User = typeof auth.$Infer.Session.user;
機能比較表
| 比較項目 | Auth.js v5 | Lucia | BetterAuth |
|---|---|---|---|
| ライセンス | ISC | MIT | MIT |
| GitHub Stars | 24k+ | 8k+ | 6k+ |
| OAuth対応 | ✅ 70+プロバイダー | ✅ 手動実装 | ✅ プラグイン |
| メール/パスワード | ✅ | ✅ | ✅ |
| マジックリンク | ✅ | ✅ | ✅ プラグイン |
| パスキー(WebAuthn) | ✅ | ✅ | ✅ プラグイン |
| 2FA/TOTP | ❌ | ❌ | ✅ プラグイン |
| セッション管理 | ✅ Cookie/JWT | ✅ セッションDB | ✅ |
| DBアダプター | ✅ Drizzle/Prisma等 | ✅ | ✅ |
| 型安全 | ★★★☆☆ | ★★★★☆ | ★★★★★ |
| App Router対応 | ✅ v5から | ✅ | ✅ |
| RBAC | ✅ カスタム | ✅ カスタム | ✅ |
| ドキュメント品質 | ★★★★☆ | ★★★☆☆ | ★★★★☆ |
認証・アクセス制御ツールはsecurityカテゴリ(/categories/security)にまとめています。IDプロバイダーのセルフホストについてはKeycloak・Authentik比較(/categories/security)も参照してください。
FAQ
Q. Auth.js v4とv5(NextAuth→Auth.js)の違いは何ですか?
A. Auth.js v5(旧NextAuth v5)の主な変更点: ①App Router完全対応(Server Components・Server Actions・ミドルウェアでauth()を直接呼べる)、②設定ファイルがpages/api/auth/[...nextauth].ts→auth.tsに一元化、③getServerSessionが不要になりawait auth()で統一、④プロバイダー名がGithubProvider→GitHub等に短縮。v4からv5への移行は設定ファイルの書き換えとimportパスの変更が主で、ビジネスロジックへの影響は少ないです。Pages Routerとの後方互換性も一定維持されています。
Q. SupabaseのAuth機能とAuth.js/Luciaはどう使い分けますか?
A. Supabaseを使っているプロジェクトでは「Supabase Auth vs Auth.js」が悩みどころです。Supabase Authの優位点: ①Supabaseダッシュボードでユーザー管理ができる、②Row Level Security(RLS)と連携してDB行レベルのアクセス制御が簡単、③メール確認・パスワードリセットのUIが組み込み。Auth.js/Luciaの優位点: ①より細かなセッション管理・カスタムフィールドの自由度、②Supabase以外のDBに移行しやすい、③プロバイダー数が豊富。推奨: Supabaseをメインにしているなら「Supabase Auth + @supabase/ssr」が最もシームレスです。SupabaseをDBとして使いつつ認証を自分でコントロールしたいならAuth.jsを@auth/drizzle-adapterでSupabaseに接続します。
Q. JWTとセッションCookieのどちらを選ぶべきですか?
A. セッションCookie(DBセッション)推奨の場面: ①ユーザーセッションを即座に無効化したい(ログアウト・アカウント停止)、②セッションのメタデータ(最終ログイン・デバイス情報)を管理したい、③セキュリティが最優先(JWTは有効期限内は無効化不可)。JWT推奨の場面: ①完全ステートレスなAPIが必要(マイクロサービス間の認証)、②DBへのセッション検証コールを減らしたい(スケール重視)。Next.jsのWebアプリなら: ①セッションCookieを基本とし、②APIレートリミット・WebSocketでJWTを補助的に使うハイブリッド構成が安全でスケーラブルです。Auth.jsはデフォルトがJWTですがadapter設定でDBセッションに切り替えられます。
Q. BetterAuthのパスキー(WebAuthn)実装はどのくらい難しいですか?
A. BetterAuthのパスキー(passkey)プラグインを使えば比較的簡単に実装できます。サーバー側: plugins: [passkey()]を追加するだけ。クライアント側: @simplewebauthn/browserがBetterAuthに同梱されており、signIn.passkey()を呼ぶだけでブラウザのパスキー認証ダイアログが開きます。難しい点: ①本番環境ではHTTPS必須(localhostは例外)、②RP ID(Relying Party ID)をドメインに合わせて設定する必要がある、③iOSのSafariとAndroidのChromeで動作確認が必要(実装の癖が異なる)。パスキーはパスワードレスで最もセキュアな認証方式として普及が進んでいます。
まとめ
| ユースケース | 推奨ツール |
|---|---|
| OAuth + シンプルなNext.js認証 | Auth.js v5 |
| セッション管理を細かく制御 | Lucia |
| 2FA・パスキー・マジックリンクを全部使いたい | BetterAuth |
| Supabaseと連携 | Supabase Auth + @supabase/ssr |