next-auth の使い方 — Next.js に認証機能を最速で導入する方法
一言でいうと
next-auth は、Next.js アプリケーションに OAuth・メール認証・JWT ベースの認証を簡単に組み込める、フルスタック認証ライブラリです。Google や GitHub などの主要プロバイダーに対応し、数十行のコードで本格的な認証基盤を構築できます。
注意: この記事は next-auth v4 系(4.24.x)を対象としています。v5(Auth.js)では API が大幅に変更されているため、バージョンにご注意ください。
どんな時に使う?
- Next.js アプリに Google / GitHub / Apple などのソーシャルログインを導入したい時 — プロバイダー設定を数行書くだけで OAuth フローが完成します
- JWT またはデータベースセッションによるユーザー管理を手軽に実装したい時 — セッション管理、CSRF 対策、Cookie ポリシーがデフォルトで安全に設定されています
- メールリンク(パスワードレス)認証を実装したい時 — Email プロバイダーを使えば、マジックリンク方式の認証を簡単に構築できます
インストール
# npm
npm install next-auth
# yarn
yarn add next-auth
# pnpm
pnpm add next-auth
基本的な使い方(next-auth セットアップ)
1. API ルートの作成
// pages/api/auth/[...nextauth].ts
import NextAuth, { NextAuthOptions } from "next-auth";
import GoogleProvider from "next-auth/providers/google";
import GitHubProvider from "next-auth/providers/github";
export const authOptions: NextAuthOptions = {
secret: process.env.NEXTAUTH_SECRET,
providers: [
GoogleProvider({
clientId: process.env.GOOGLE_CLIENT_ID!,
clientSecret: process.env.GOOGLE_CLIENT_SECRET!,
}),
GitHubProvider({
clientId: process.env.GITHUB_ID!,
clientSecret: process.env.GITHUB_SECRET!,
}),
],
};
export default NextAuth(authOptions);
2. 環境変数の設定
# .env.local
NEXTAUTH_URL=http://localhost:3000
NEXTAUTH_SECRET=your-random-secret-string # openssl rand -base64 32 で生成推奨
GOOGLE_CLIENT_ID=xxx
GOOGLE_CLIENT_SECRET=xxx
GITHUB_ID=xxx
GITHUB_SECRET=xxx
3. SessionProvider でアプリ全体をラップ
// pages/_app.tsx
import { SessionProvider } from "next-auth/react";
import type { AppProps } from "next/app";
export default function App({
Component,
pageProps: { session, ...pageProps },
}: AppProps) {
return (
<SessionProvider session={session}>
<Component {...pageProps} />
</SessionProvider>
);
}
4. コンポーネントでセッションを利用
// components/AuthButton.tsx
import { useSession, signIn, signOut } from "next-auth/react";
export default function AuthButton() {
const { data: session, status } = useSession();
if (status === "loading") return <p>読み込み中...</p>;
if (session) {
return (
<div>
<p>ログイン中: {session.user?.email}</p>
<button onClick={() => signOut()}>ログアウト</button>
</div>
);
}
return <button onClick={() => signIn()}>ログイン</button>;
}
よく使う API — next-auth の主要機能
1. useSession() — クライアント側でセッション取得
最も頻繁に使うフックです。status は "loading" | "authenticated" | "unauthenticated" の 3 値を返します。
import { useSession } from "next-auth/react";
function Dashboard() {
const { data: session, status } = useSession({
required: true, // 未認証時は自動でサインインページへリダイレクト
onUnauthenticated() {
// required: true の場合のカスタムハンドラ(任意)
console.log("認証が必要です");
},
});
if (status === "loading") return <p>読み込み中...</p>;
return <p>ようこそ、{session!.user?.name} さん</p>;
}
2. getServerSession() — サーバー側でセッション取得
API ルートや getServerSideProps でセッションを安全に取得します。getSession() よりも推奨されます(余分な HTTP リクエストが発生しないため)。
// pages/api/protected.ts
import type { NextApiRequest, NextApiResponse } from "next";
import { getServerSession } from "next-auth/next";
import { authOptions } from "./auth/[...nextauth]";
export default async function handler(
req: NextApiRequest,
res: NextApiResponse
) {
const session = await getServerSession(req, res, authOptions);
if (!session) {
return res.status(401).json({ error: "認証が必要です" });
}
return res.json({
message: `こんにちは、${session.user?.name} さん`,
});
}
// pages/dashboard.tsx — getServerSideProps での利用
import type { GetServerSidePropsContext } from "next";
import { getServerSession } from "next-auth/next";
import { authOptions } from "./api/auth/[...nextauth]";
export async function getServerSideProps(context: GetServerSidePropsContext) {
const session = await getServerSession(context.req, context.res, authOptions);
if (!session) {
return { redirect: { destination: "/api/auth/signin", permanent: false } };
}
return { props: { session } };
}
3. signIn() / signOut() — 認証フローの制御
import { signIn, signOut } from "next-auth/react";
// 特定のプロバイダーを指定してサインイン
function LoginButtons() {
return (
<div>
{/* Google でサインイン */}
<button onClick={() => signIn("google")}>Google でログイン</button>
{/* GitHub でサインイン(コールバックURL指定) */}
<button onClick={() => signIn("github", { callbackUrl: "/dashboard" })}>
GitHub でログイン
</button>
{/* Credentials プロバイダーでサインイン(リダイレクトなし) */}
<button
onClick={async () => {
const result = await signIn("credentials", {
redirect: false,
email: "user@example.com",
password: "password123",
});
if (result?.error) {
console.error("ログイン失敗:", result.error);
}
}}
>
メールでログイン
</button>
{/* サインアウト */}
<button onClick={() => signOut({ callbackUrl: "/" })}>ログアウト</button>
</div>
);
}
4. Callbacks — セッション・JWT のカスタマイズ
callbacks を使うと、セッションオブジェクトに独自のフィールドを追加できます。
// pages/api/auth/[...nextauth].ts
import NextAuth, { NextAuthOptions } from "next-auth";
import GoogleProvider from "next-auth/providers/google";
export const authOptions: NextAuthOptions = {
secret: process.env.NEXTAUTH_SECRET,
providers: [
GoogleProvider({
clientId: process.env.GOOGLE_CLIENT_ID!,
clientSecret: process.env.GOOGLE_CLIENT_SECRET!,
}),
],
callbacks: {
async jwt({ token, account, profile }) {
// 初回サインイン時に追加情報を token に格納
if (account) {
token.accessToken = account.access_token;
token.id = token.sub;
}
return token;
},
async session({ session, token }) {
// クライアントに公開する session オブジェクトをカスタマイズ
session.accessToken = token.accessToken as string;
session.user.id = token.id as string;
return session;
},
async signIn({ user, account, profile }) {
// 特定ドメインのメールのみ許可する例
const email = user.email ?? "";
if (email.endsWith("@yourcompany.com")) {
return true;
}
return false; // false を返すとサインイン拒否
},
},
};
export default NextAuth(authOptions);
型を拡張する場合は、以下のように宣言マージを行います。
// types/next-auth.d.ts
import "next-auth";
declare module "next-auth" {
interface Session {
accessToken: string;
user: {
id: string;
name?: string | null;
email?: string | null;
image?: string | null;
};
}
}
declare module "next-auth/jwt" {
interface JWT {
accessToken?: string;
id?: string;
}
}
5. Credentials Provider — ID/パスワード認証
独自のユーザーデータベースと組み合わせた認証を実装できます。
// pages/api/auth/[...nextauth].ts
import NextAuth, { NextAuthOptions } from "next-auth";
import CredentialsProvider from "next-auth/providers/credentials";
export const authOptions: NextAuthOptions = {
secret: process.env.NEXTAUTH_SECRET,
session: {
strategy: "jwt", // Credentials 利用時は JWT 必須
},
providers: [
CredentialsProvider({
name: "メールアドレス",
credentials: {
email: { label: "メール", type: "email", placeholder: "user@example.com" },
password: { label: "パスワード", type: "password" },
},
async authorize(credentials) {
// ここで DB 問い合わせやパスワード検証を行う
const user = await findUserByEmail(credentials?.email ?? "");
if (user && await verifyPassword(credentials?.password ?? "", user.hashedPassword)) {
return { id: user.id, name: user.name, email: user.email };
}
return null; // null を返すとサインイン失敗
},
}),
],
pages: {
signIn: "/auth/signin", // カスタムサインインページ
error: "/auth/error",
},
};
export default NextAuth(authOptions);
類似パッケージとの比較
| 特徴 | next-auth (v4) | Auth.js (v5) | clerk | lucia |
|---|---|---|---|---|
| 対応フレームワーク | Next.js 専用 | Next.js, SvelteKit, Express 等 | Next.js, React, Remix 等 | フレームワーク非依存 |
| ホスティング | セルフホスト | セルフホスト | SaaS(マネージド) | セルフホスト |
| OAuth プロバイダー数 | 60+ | 80+ | 20+ | 自前実装 |
| DB セッション | ✅ | ✅ | N/A(SaaS管理) | ✅ |
| JWT セッション | ✅ | ✅ | N/A | ❌(DB のみ) |
| Credentials 認証 | ✅(制限あり) | ✅(制限あり) | ✅ | ✅ |
| 料金 | 無料 | 無料 | フリーミアム | 無料 |
| App Router 対応 | 部分的 | ネイティブ対応 | ✅ | ✅ |
| 学習コスト | 低〜中 | 中 | 低 | 中〜高 |
補足: next-auth v4 の後継が Auth.js (v5) です。新規プロジェクトで App Router を使う場合は v5 への移行を検討してください。ただし v4 は依然として広く使われており、安定しています。
注意点・Tips
1. NEXTAUTH_SECRET は必ず設定する
本番環境では NEXTAUTH_SECRET が未設定だとエラーになります。以下のコマンドで安全なシークレットを生成してください。
openssl rand -base64 32
2. getServerSession を優先的に使う
クライアント側の getSession() はサーバーに HTTP リクエストを送信してセッションを取得します。サーバーサイド(API ルート、getServerSideProps)では getServerSession() を使うことで、不要なネットワークラウンドトリップを回避できます。
3. Credentials Provider の制限を理解する
Credentials Provider を使う場合、データベースセッション(strategy: "database")は利用できません。JWT 戦略のみ対応です。また、useSession() の update や refetchInterval によるセッション更新は JWT の有効期限に依存するため、リアルタイムなユーザー情報の反映には工夫が必要です。
4. Middleware でルート保護する
Next.js の Middleware と組み合わせることで、ページ単位の認証チェックを一元管理できます。
// middleware.ts
export { default } from "next-auth/middleware";
export const config = {
matcher: ["/dashboard/:path*", "/settings/:path*"],
};
より細かい制御が必要な場合:
// middleware.ts
import { withAuth } from "next-auth/middleware";
export default withAuth(
function middleware(req) {
// 認証済みユーザーのみここに到達
console.log("token:", req.nextauth.token);
},
{
callbacks: {
authorized: ({ token }) => token?.role === "admin",
},
}
);
export const