Next.js Middleware:堅牢な認証と認可の構築

Table of Contents
認証と認可は、あらゆるセキュアなウェブアプリケーションの基盤です。これまでNext.jsでは、ルートを保護するために、コンポーネントを高階コンポーネント(HOC)でラップしたり、ページごとにgetServerSidePropsでチェックを実行したりしていました。しかし、Next.js App RouterとEdge Middlewareの成熟により、セキュリティを処理するための、はるかに優れた、一元化された、高性能な方法が利用できるようになりました。
2026年、Next.js MiddlewareはEdgeで実行されます。これは、認証チェックがユーザーに非常に近い場所で、リクエストがオリジンサーバーに到達する前に実行されることを意味します。この記事では、Next.js Middlewareを使用して、堅牢でスケーラブルな認証および認可パイプラインを構築する方法を探ります。
認証にMiddlewareを使用する理由
Middlewareを使用すると、リクエストをインターセプトし、有効なセッションまたはトークンをチェックし、リクエストを通過させるか、書き換えるか、ユーザーをリダイレクトするかを決定できます。
主な利点:
- 一元化: 認証ロジックを何十ものページやレイアウトに分散させる必要がなくなります。単一の
middleware.tsファイルでアプリケーション全体を保護できます。 - パフォーマンス: Edgeランタイム(Vercel Edge FunctionsやCloudflare Workersなど)で実行されるため、コールドスタートがほぼゼロで、レイテンシーが最小限に抑えられます。ページがレンダリングを開始する前にチェックが実行されます。
- セキュリティ: 認証されていないリクエストをEdgeで停止することで、オリジンサーバーとデータベースへの負荷を軽減します。
基本的な認証フロー
当社のゼロリークブラウザデコーダーを使用して、JWTペイロード、ヘッダークレーム、および有効期限タイムスタンプをリアルタイムでテストおよび検査してください。
クッキーに保存されたJSON Webトークン(JWT)を使用した標準的な実装を見てみましょう。
1. Middlewareのセットアップ
プロジェクトのルート(または使用している場合はsrcディレクトリ)にmiddleware.tsファイルを作成します。
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'
import { verifyJwtToken } from '@/lib/auth' // Your custom JWT verifier
export async function middleware(request: NextRequest) {
const token = request.cookies.get('auth-token')?.value
const isAuthPage = request.nextUrl.pathname.startsWith('/login') ||
request.nextUrl.pathname.startsWith('/register')
// 1. Check if token exists and is valid
const verifiedToken = token && (await verifyJwtToken(token).catch((err) => {
console.error('Failed to verify token', err)
}))
// 2. Redirect unauthenticated users away from protected routes
if (!verifiedToken) {
if (!isAuthPage && request.nextUrl.pathname.startsWith('/dashboard')) {
const loginUrl = new URL('/login', request.url)
loginUrl.searchParams.set('callbackUrl', request.nextUrl.pathname)
return NextResponse.redirect(loginUrl)
}
}
// 3. Redirect authenticated users away from auth pages
if (verifiedToken && isAuthPage) {
return NextResponse.redirect(new URL('/dashboard', request.url))
}
// 4. Pass the request through if all checks pass
return NextResponse.next()
}
// See "Matching Paths" below
export const config = {
matcher: ['/dashboard/:path*', '/login', '/register'],
}
2. パスのマッチング(matcher)
matcherの設定は非常に重要です。これは、どのルートがミドルウェアをトリガーするかをNext.jsに伝えます。すべてのリクエスト(静的アセットやAPIルートを含む)でミドルウェアを実行するのは非効率的です。
['/dashboard/:path*', '/login', '/register']を指定することで、認証ロジックが必要な場所でのみ実行されるようにします。
認可の処理(ロールベースアクセス制御 - RBAC)
認証は「あなたは誰ですか?」と尋ねます。認可は「あなたは何を許可されていますか?」と尋ねます。ユーザーが認証されると、そのユーザーのロールや権限をチェックする必要があることがよくあります。
ミドルウェアを拡張してRBACを簡単に処理できます。
// ... previous imports
import { verifyJwtToken } from '@/lib/auth'
export async function middleware(request: NextRequest) {
const token = request.cookies.get('auth-token')?.value
const verifiedToken = token && (await verifyJwtToken(token))
// ... standard auth checks
// Handle Authorization
if (verifiedToken) {
const userRole = verifiedToken.role // Assuming role is encoded in the JWT
// Protect admin routes
if (request.nextUrl.pathname.startsWith('/admin')) {
if (userRole !== 'ADMIN') {
// User is authenticated, but not authorized
return NextResponse.redirect(new URL('/unauthorized', request.url))
}
}
}
return NextResponse.next()
}
export const config = {
matcher: ['/dashboard/:path*', '/admin/:path*', '/login'],
}
Middlewareにおけるセキュリティのベストプラクティス
- 軽量に保つ: Edgeランタイムにはサイズと実行時間の制限があります。ミドルウェアで重いデータベースクエリを実行しないでください。JWT検証のような高速でステートレスなチェックに依存してください。
- Edge JWTには
joseを使用する: 標準のNode.jsjsonwebtokenはNodeの暗号化APIに依存していますが、これらはEdgeでは利用できません。ミドルウェアでトークンの署名と検証を行うには、joseのようなライブラリを使用してください。 - セキュアなクッキー: XSSおよびCSRF攻撃を防ぐために、認証クッキーが
HttpOnly、Secure、およびSameSite=laxまたはstrictで設定されていることを確認してください。 - 適切なエラー処理: トークン検証が失敗した場合(例:署名の期限切れ)、エラーを適切にキャッチしてログインにリダイレクトし、500エラーを引き起こす未処理の例外をスローしないようにしてください。
高度なトピック: サーバーコンポーネントへのデータ渡し
一般的な課題は、ミドルウェアでトークンを検証した後、トークンを再検証せずにユーザーデータをサーバーコンポーネントに渡す方法です。
ミドルウェアでリクエストヘッダーを変更し、サーバーコンポーネントでそれらを読み取ることができます。
ミドルウェア内:
if (verifiedToken) {
const requestHeaders = new Headers(request.headers)
requestHeaders.set('x-user-id', verifiedToken.userId)
return NextResponse.next({
request: {
headers: requestHeaders,
},
})
}
サーバーコンポーネント内(page.tsx):
import { headers } from 'next/headers'
export default function DashboardPage() {
const headersList = headers()
const userId = headersList.get('x-user-id')
return <div>Welcome User: {userId}</div>
}
まとめ
Next.js Middlewareは、認証と認可を処理するための強力なEdge最適化レイヤーを提供します。これらのチェックを一元化することで、コンポーネント階層を大幅に簡素化し、パフォーマンスを向上させ、アプリケーション全体のセキュリティ体制を強化できます。ステートレスなJWTと慎重なルートマッチングを組み合わせることで、最新のNext.jsアーキテクチャのバックボーンを形成します。
こちらもおすすめです
Free In-Browser Developer Tools
Clean AI CLI logs, build cron expressions, decode JWTs, and calculate chmod permissions offline.
Related Articles

TypeScriptだけでは不十分:Next.jsでZodを使ったエンドツーエンドの型安全性
TypeScriptがランタイムで消失する理由、APIやServer Actionの境界で静的型が機能しない理由、そしてZodがいかに確実なスキーマ検証と型推論を提供するのかを学びましょう。
Read more
Next.jsにおけるsuppressHydrationWarning: 安全な利用法とデバッグの完全ガイド
Next.jsのsuppressHydrationWarningについて、安全な利用法とデバッグ方法を実証済みの本番環境での例を交えて網羅的に解説する包括的なガイドです。
Read more
gRPCとConnectRPC:最新のマイクロサービスとブラウザネイティブなProtobuf
TypeScriptとGoにおけるgRPCとConnectRPCのアーキテクチャを評価し、HTTP/1.1とHTTP/2ストリーミング、Envoyプロキシ不要のブラウザクライアント、p99 RPCレイテンシについて解説します。
Read more