はじめに
認証機能の実装って、正直なところ面倒なんですよね。
セッション管理、トークンの発行、OAuthのコールバック処理、セキュリティ対策...やることが多すぎて、本来作りたい機能に集中できない。30代になって思うのは、こういう「車輪の再発明」に時間を費やすのはもったいないということ。
NextAuth.js(現Auth.js)は、そんな認証実装の面倒さを一気に解決してくれるライブラリです。GitHubで28,000スター以上、毎月約900万回のnpmダウンロード。Next.js界隈では事実上のスタンダードになっています。
個人的には、このライブラリを知ってから認証実装に対する苦手意識がかなり減りました。
NextAuth.jsとは
NextAuth.jsは、Next.js向けに設計されたオープンソースの認証ライブラリです。現在は「Auth.js」としてリブランディングされ、Next.js以外のフレームワーク(SvelteKit、Express、Qwikなど)にも対応しています。
「Authentication for the Web」がキャッチコピーで、Web標準のAPIをベースに構築されているのが特徴。ISCライセンスで公開されており、906人以上のコントリビューターが開発に参加しています。
現在の主要バージョンはv4系(next-auth v4.24.13)で、v5系(Auth.js)も並行して開発が進んでいます。
特徴・メリット
1. プロバイダーが豊富
これ、意外と重要なポイントなんですけど、NextAuth.jsは主要なOAuthプロバイダーにほぼ対応しています。
- Google、GitHub、Twitter、Facebook
- Apple、Discord、Slack
- Azure AD、Auth0、Okta
- その他数十種類
プロバイダーの追加も数行で済む。「Googleログインを追加して」と言われても、30分もあれば対応できます。
2. データベースオプション
データベースを使わない「JWT only」モードから、フル機能のセッション管理まで選べます。
対応データベース:
- MySQL、PostgreSQL、SQLite
- MongoDB、DynamoDB
- Prisma、Drizzle、TypeORMなど各種ORM
個人的には、この柔軟性が一番のメリットだと思います。小規模なら JWT だけで済ませて、規模が大きくなったらDBを追加する、みたいな段階的な導入ができる。
3. セキュリティがデフォルトで堅い
正直なところ、認証のセキュリティを自前で完璧に実装するのは難しい。NextAuth.jsは以下の対策がデフォルトで入っています:
- CSRF トークン保護(POSTルートすべて)
- 暗号化されたJWT(JWE with A256CBC-HS512)
- セッション同期(タブ間でのログアウト同期)
- HttpOnly、Secure Cookieの適切な設定
この辺を自分で実装しようとすると、かなりの工数がかかるんですよね。
4. TypeScript完全対応
型定義が充実していて、TypeScriptで書くときのストレスがない。セッション情報の型拡張も簡単にできます。
5. 認証方式が多様
OAuth以外にも対応しています:
- Email/Passwordless(マジックリンク)
- WebAuthn/Passkeys(生体認証)
- Credentials(ID/パスワード)
特にWebAuthn対応は、パスワードレス認証を実装したい場合に重宝します。
インストール方法
前提条件
- Next.js 13.4以降のプロジェクト
- Node.js 18以降
インストール
npm install next-auth
これだけ。追加の依存関係は必要ありません。
環境変数の設定
.env.localファイルを作成:
NEXTAUTH_URL=http://localhost:3000
NEXTAUTH_SECRET=your-secret-key-here
NEXTAUTH_SECRETは本番環境では必ずランダムな文字列を設定してください。以下のコマンドで生成できます:
openssl rand -base64 32
基本的な使い方
App Routerでのセットアップ(Next.js 13.4+)
まず、APIルートを作成します。
// app/api/auth/[...nextauth]/route.ts
import NextAuth from "next-auth"
import GithubProvider from "next-auth/providers/github"
const handler = NextAuth({
providers: [
GithubProvider({
clientId: process.env.GITHUB_ID!,
clientSecret: process.env.GITHUB_SECRET!,
}),
],
})
export { handler as GET, handler as POST }
たったこれだけで、GitHubログインが動きます。正直、最初に動かしたときは「え、これだけ?」と驚きました。
SessionProviderの設定
クライアントコンポーネントでセッション情報を使うには、SessionProviderでラップします。
// app/providers.tsx
"use client"
import { SessionProvider } from "next-auth/react"
export function Providers({ children }: { children: React.ReactNode }) {
return <SessionProvider>{children}</SessionProvider>
}
// app/layout.tsx
import { Providers } from "./providers"
export default function RootLayout({
children,
}: {
children: React.ReactNode
}) {
return (
<html lang="ja">
<body>
<Providers>{children}</Providers>
</body>
</html>
)
}
ログイン/ログアウトの実装
"use client"
import { useSession, signIn, signOut } from "next-auth/react"
export default function LoginButton() {
const { data: session } = useSession()
if (session) {
return (
<div>
<p>ログイン中: {session.user?.name}</p>
<button onClick={() => signOut()}>ログアウト</button>
</div>
)
}
return (
<button onClick={() => signIn("github")}>
GitHubでログイン
</button>
)
}
useSessionフックでセッション情報を取得、signInとsignOutで認証操作。シンプルで分かりやすい。
サーバーコンポーネントでの使用
// app/profile/page.tsx
import { getServerSession } from "next-auth"
import { authOptions } from "@/app/api/auth/[...nextauth]/route"
import { redirect } from "next/navigation"
export default async function ProfilePage() {
const session = await getServerSession(authOptions)
if (!session) {
redirect("/api/auth/signin")
}
return (
<div>
<h1>プロフィール</h1>
<p>名前: {session.user?.name}</p>
<p>メール: {session.user?.email}</p>
</div>
)
}
サーバーコンポーネントではgetServerSessionを使います。認証済みかどうかでリダイレクトする処理も簡単。
実践的なユースケース
複数プロバイダーの設定
import NextAuth from "next-auth"
import GithubProvider from "next-auth/providers/github"
import GoogleProvider from "next-auth/providers/google"
import DiscordProvider from "next-auth/providers/discord"
export const authOptions = {
providers: [
GithubProvider({
clientId: process.env.GITHUB_ID!,
clientSecret: process.env.GITHUB_SECRET!,
}),
GoogleProvider({
clientId: process.env.GOOGLE_CLIENT_ID!,
clientSecret: process.env.GOOGLE_CLIENT_SECRET!,
}),
DiscordProvider({
clientId: process.env.DISCORD_CLIENT_ID!,
clientSecret: process.env.DISCORD_CLIENT_SECRET!,
}),
],
}
プロバイダーを配列に追加するだけ。ログインページには自動で選択肢が表示されます。
データベースとの連携(Prisma)
import { PrismaAdapter } from "@auth/prisma-adapter"
import { PrismaClient } from "@prisma/client"
const prisma = new PrismaClient()
export const authOptions = {
adapter: PrismaAdapter(prisma),
providers: [
// プロバイダー設定
],
}
Adapterを設定するだけで、ユーザー情報がデータベースに保存されるようになります。アカウントの紐付け、セッション管理もすべて自動。
セッション情報のカスタマイズ
export const authOptions = {
providers: [...],
callbacks: {
async session({ session, token, user }) {
// セッションにユーザーIDを追加
if (session.user) {
session.user.id = token.sub
}
return session
},
async jwt({ token, user, account }) {
// JWTに追加情報を保存
if (user) {
token.role = user.role
}
return token
},
},
}
callbacksを使えば、セッションやトークンに独自の情報を追加できます。
型拡張
TypeScriptで型安全に使うための拡張:
// types/next-auth.d.ts
import { DefaultSession } from "next-auth"
declare module "next-auth" {
interface Session {
user: {
id: string
role: string
} & DefaultSession["user"]
}
interface User {
role: string
}
}
declare module "next-auth/jwt" {
interface JWT {
role: string
}
}
これでsession.user.idやsession.user.roleに型がつきます。
認証ページのカスタマイズ
export const authOptions = {
providers: [...],
pages: {
signIn: "/login",
signOut: "/logout",
error: "/auth/error",
newUser: "/welcome",
},
}
デフォルトの認証ページを使わず、独自のページを指定できます。ブランドに合わせたUIを作りたい場合に便利。
ミドルウェアでの保護
// middleware.ts
export { default } from "next-auth/middleware"
export const config = {
matcher: ["/dashboard/:path*", "/api/protected/:path*"],
}
特定のパスを認証必須にするのも、ミドルウェア一行で済みます。
よくある質問
JWTとデータベースセッション、どっちがいい?
個人的には、以下の基準で判断しています:
- JWT: 小規模アプリ、サーバーレス環境、即座にログアウトさせる必要がない場合
- データベースセッション: 大規模アプリ、即座のセッション無効化が必要な場合、複数デバイス管理
コスパ的に、最初はJWTで始めて、必要になったらDBに移行するのが楽です。
Credentialsプロバイダーは使っていい?
公式ドキュメントでも注意書きがありますが、ID/パスワード認証は推奨されていません。理由は:
- パスワードの漏洩リスク
- ブルートフォース攻撃への対策が必要
- ユーザー体験がOAuthより劣る
どうしても必要な場合は、レート制限やアカウントロックを自前で実装する必要があります。
まとめ
NextAuth.jsを導入して感じた変化:
- セットアップ: 15分で基本的な認証が動く
- 学習コスト: Reactが分かれば即使える
- セキュリティ: ベストプラクティスがデフォルトで適用
- 拡張性: callbacksで柔軟にカスタマイズ可能
- 保守性: プロバイダー追加が数行で済む
正直なところ、Next.jsで認証を実装するならNextAuth.js一択ですね。自前実装の苦労を知っている身としては、この手軽さは革命的。
特にOAuth認証の実装が劇的に楽になる。GitHub、Google、Twitterのログインを全部対応しても、設定ファイルは100行以下で収まります。
まだ試していない人は、まず個人プロジェクトで使ってみてください。認証実装に対する考え方が変わると思います。