TOOLS BOX/ガイド/Next.js 認証方式比較
Concept

Next.js 認証方式比較

Middleware / Layout 保護 / Server Component 個別確認の3方式を比較し、Next.js App Router で認証判定をどこに置くべきかの選び分けを整理するガイド。

nextjsauthmiddlewarelayoutserver-componentredirectsessioncookie

どういう場面で使うか

  • ·Middleware: アプリ全体または複数ルートをまとめて保護したいとき
  • ·Layout 保護: /(dashboard) などのルートグループ配下を一括保護したいとき
  • ·Server Component 個別確認: ページごとに認証条件や表示内容を柔軟に制御したいとき

注意点 / Pitfalls

  • ·Middleware は Edge Runtime で動くため、Prisma などの Node.js 専用ライブラリを直接使えない
  • ·Layout 保護はレイアウト内のデータ取得エラーがレイアウト配下全体に影響する
  • ·Server Component 個別確認はページ単位で書くため共通化しないと重複が増える
  • ·Middleware と Layout・Server Component を二重に保護する場合、どちらが責務を持つか明確にしておく

補足

3方式は排他的でなく組み合わせて使うことが多い。Middleware でルートを一括保護しつつ、Server Component でユーザー固有の表示切り替えを行うパターンが典型的。

比較表

MiddlewareLayout 保護Server Component 個別確認
実行タイミングルート到達前(Edge)レイアウト描画時(Server)ページ描画時(Server)
保護の単位パターンマッチ(複数ルート一括)レイアウト配下全体ページ単位
柔軟な条件分岐限定的中程度高い
リダイレクト方法NextResponse.redirect()redirect()(next/navigation)redirect()(next/navigation)
Node.js ライブラリ使用不可(Edge Runtime)
重複リスク低い低いページ数が増えると高くなる

各方式が向く場面

Middleware

// middleware.ts
import { NextResponse } from "next/server";
import type { NextRequest } from "next/server";

export function middleware(request: NextRequest) {
  const session = request.cookies.get("session_id");
  if (!session) {
    return NextResponse.redirect(new URL("/login", request.url));
  }
  return NextResponse.next();
}

export const config = {
  matcher: ["/dashboard/:path*", "/admin/:path*"],
};

向く場面:

  • アプリ全体、または /dashboard 配下など複数ルートをまとめてガードしたいとき
  • セッション Cookie の有無だけで判定できる単純な認証チェック

注意点: Middleware は Edge Runtime で動作するため、Prisma などの Node.js 専用ライブラリは使えません。Cookie の読み取りや JWT の検証など、Edge で動く軽い処理に限定します。重いロジックは Server Component に任せます。

Layout 保護

// app/(dashboard)/layout.tsx
import { cookies } from "next/headers";
import { redirect } from "next/navigation";

export default async function DashboardLayout({ children }) {
  const cookieStore = await cookies();
  if (!cookieStore.get("session_id")) {
    redirect("/login");
  }
  return <div>{children}</div>;
}

向く場面:

  • ルートグループ((dashboard) など)配下のページをまとめて保護したいとき
  • Prisma など Node.js ライブラリでセッション検証をしたいとき
  • レイアウト共通のデータ取得(ユーザー情報など)と認証チェックをまとめたいとき

注意点: レイアウトは配下のすべてのページで実行されます。レイアウト内で例外が発生すると配下全体に影響するため、エラーハンドリングを適切に設けます。

Server Component 個別確認

// app/dashboard/settings/page.tsx
import { cookies } from "next/headers";
import { redirect } from "next/navigation";

export default async function SettingsPage() {
  const cookieStore = await cookies();
  if (!cookieStore.get("session_id")) {
    redirect("/login");
  }
  // ページ固有の処理
}

向く場面:

  • ページごとに異なる認証条件(権限レベルの違いなど)を持たせたいとき
  • 認証状態によって表示内容を細かく切り替えたいとき
  • 認証チェックとデータ取得を同じコンポーネントで管理したいとき

注意点: ページが増えると認証チェックのコードが重複します。共通のヘルパー関数(例: requireAuth())に切り出して再利用するパターンが有効です。

実行タイミングの違い

リクエスト
    │
    ▼
【Middleware】← ルートに到達する前(Edge)
    │         未認証 → /login へリダイレクト
    │
    ▼
【Layout 保護】← レイアウト描画時(Server)
    │            未認証 → /login へリダイレクト
    │
    ▼
【Server Component】← ページ描画時(Server)
                      未認証 → /login へリダイレクト

早い段階で弾くほど後続処理のコストが減ります。ただし Edge での実行制約(Middleware)と Node.js での実行柔軟性(Layout / Server Component)のトレードオフがあります。

ルート単位 / コンポーネント単位の違い

  • Middleware: matcher で URL パターンを指定して複数ルートを一括保護。コンポーネントツリーの外で動くため、React の Context や Server Component の機能は使えない
  • Layout 保護: App Router のレイアウト階層に従って保護範囲が決まる。(dashboard) などのルートグループと組み合わせるとセクション単位の保護が自然に書ける
  • Server Component 個別確認: ページ単位で条件を自由に書ける。if (user.role !== 'admin') redirect('/403') のような権限チェックも自然

よくある選び方

ルート全体を一括でガードしたいか?
├── Yes → Middleware(Cookie の有無だけで判定できるなら最適)
│         ※ Edge で動かない処理が必要なら Layout 保護に
└── No
    ├── セクション(/(dashboard) など)単位でまとめて保護したいか?
    │   └── Yes → Layout 保護
    └── ページごとに条件・表示を柔軟に制御したいか?
        └── Yes → Server Component 個別確認
                  ※ 重複を防ぐため requireAuth() 関数に共通化する

組み合わせパターン

3方式は排他的ではありません。典型的な組み合わせ:

  • Middleware + Server Component: Middleware でルートを一括ガード(Cookie の存在チェック)し、Server Component でセッションの有効性確認とユーザー情報取得を行う
  • Layout + Server Component: Layout でセクション全体を保護しつつ、各ページで権限レベルに応じた表示切り替えを行う

二重に保護する場合は「どちらが何の責務を持つか」を明確にしておくと、後から修正しやすくなります。

関連サンプルの見どころ

  • nextjs-middleware-auth: Middleware での Cookie チェックとリダイレクトパターン
  • nextjs-protected-layout: Layout 保護でルートグループをまとめてガードするパターン
  • nextjs-auth-redirect: Server Component でセッション確認して条件分岐リダイレクトするパターン

未認証・権限不足・フォーム失敗の失敗分岐の判断 → 認証・権限チェックの失敗分岐

関連ドキュメント

関連サンプル

同じテーマや技術スタックを使った実装例