Next.js での認証実装方法
認証を理解することは、アプリケーションのデータを保護するために重要です。このページでは、React と Next.js の機能を使って認証を実装する方法をガイドします。
始める前に、プロセスを3つの概念に分解すると理解しやすくなります:
- 認証 (Authentication): ユーザーが自分自身であることを確認します。ユーザー名とパスワードなど、ユーザーが持っている情報を使って本人確認を行います。
- セッション管理 (Session Management): リクエストを跨いでユーザーの認証状態を追跡します。
- 認可 (Authorization): ユーザーがアクセスできるルートやデータを決定します。
この図は、React と Next.js の機能を使った認証フローを示しています:

このページの例では、教育目的で基本的なユーザー名とパスワードによる認証を説明します。カスタム認証ソリューションを実装することも可能ですが、セキュリティを強化し簡素化するため、認証ライブラリの使用を推奨します。これらは認証、セッション管理、認可のための組み込みソリューションに加え、ソーシャルログイン、多要素認証、ロールベースのアクセス制御などの追加機能を提供します。認証ライブラリセクションで一覧を確認できます。
認証 (Authentication)
サインアップとログイン機能
ユーザーの認証情報を取得し、フォームフィールドを検証して認証プロバイダーのAPIやデータベースを呼び出すために、<form>
要素と React の Server Actions、そして useActionState
を使用できます。
Server Actions は常にサーバー上で実行されるため、認証ロジックを処理する安全な環境を提供します。
以下はサインアップ/ログイン機能を実装する手順です:
1. ユーザー認証情報の取得
ユーザー認証情報を取得するには、送信時に Server Action を呼び出すフォームを作成します。例えば、ユーザーの名前、メールアドレス、パスワードを受け取るサインアップフォーム:
2. サーバー上でのフォームフィールドの検証
Server Action を使用して、サーバー上でフォームフィールドを検証します。認証プロバイダーがフォーム検証を提供していない場合、Zod や Yup などのスキーマ検証ライブラリを使用できます。
Zod を例にすると、適切なエラーメッセージを含むフォームスキーマを定義できます:
認証プロバイダーのAPIやデータベースへの不要な呼び出しを防ぐため、フォームフィールドが定義されたスキーマに一致しない場合、Server Action で早期に return
できます。
<SignupForm />
に戻り、React の useActionState
フックを使用して、フォーム送信中に検証エラーを表示できます:
知っておくと便利:
- React 19 では、
useFormStatus
が返すオブジェクトに data、method、action などの追加キーが含まれます。React 19 を使用していない場合、pending
キーのみが利用可能です。- データを変更する前に、ユーザーがその操作を実行する権限を持っていることを常に確認してください。認証と認可を参照してください。
3. ユーザー作成または認証情報の確認
フォームフィールドの検証後、認証プロバイダーのAPIやデータベースを呼び出して新しいユーザーアカウントを作成するか、既存ユーザーを確認できます。
前の例からの続き:
ユーザーアカウントの作成または認証情報の確認に成功したら、ユーザーの認証状態を管理するセッションを作成できます。セッション管理戦略に応じて、セッションはクッキーやデータベース、または両方に保存されます。セッション管理セクションに進んで詳細を確認してください。
ヒント:
- 上記の例は教育的な目的で認証手順を分解しているため冗長です。独自の安全なソリューションを実装すると複雑になりやすい点が強調されています。認証ライブラリを使用してプロセスを簡素化することを検討してください。
- ユーザー体験を向上させるため、登録フローの早い段階で重複するメールアドレスやユーザー名を確認することをお勧めします。例えば、ユーザーがユーザー名を入力中や入力フィールドからフォーカスが外れた時点で確認できます。これにより不要なフォーム送信を防ぎ、即時のフィードバックを提供できます。use-debounceなどのライブラリを使用してこれらの確認の頻度を管理できます。
セッション管理
セッション管理により、ユーザーの認証状態がリクエスト間で維持されます。セッションやトークンの作成、保存、更新、削除が含まれます。
セッションには2つのタイプがあります:
- ステートレス: セッションデータ(またはトークン)がブラウザのクッキーに保存されます。クッキーは各リクエストとともに送信され、サーバーでセッションを検証できます。この方法はシンプルですが、正しく実装されていないと安全性が低くなる可能性があります。
- データベース: セッションデータがデータベースに保存され、ユーザーのブラウザには暗号化されたセッションIDのみが送信されます。この方法はより安全ですが、複雑でサーバーリソースを多く消費する可能性があります。
知っておくと良いこと: どちらの方法も、または両方を使用できますが、iron-sessionやJoseなどのセッション管理ライブラリの使用をお勧めします。
ステートレスセッション
ステートレスセッションを作成・管理するには、いくつかの手順が必要です:
- セッションの署名に使用する秘密鍵を生成し、環境変数として保存
- セッション管理ライブラリを使用してセッションデータの暗号化/復号化ロジックを記述
- Next.jsの
cookies
APIを使用してクッキーを管理
上記に加えて、ユーザーがアプリケーションに戻ったときにセッションを更新(またはリフレッシュ)する機能と、ユーザーがログアウトしたときにセッションを削除する機能を追加することを検討してください。
知っておくと良いこと: 認証ライブラリにセッション管理機能が含まれているか確認してください。
1. 秘密鍵の生成
セッションの署名に使用する秘密鍵を生成する方法はいくつかあります。例えば、ターミナルでopenssl
コマンドを使用できます:
このコマンドは、環境変数ファイルに保存できる32文字のランダムな文字列を生成します:
この鍵はセッション管理ロジックで参照できます:
2. セッションの暗号化と復号化
次に、選択したセッション管理ライブラリを使用してセッションを暗号化および復号化できます。前の例の続きとして、Jose(Edge Runtimeと互換性あり)とReactのserver-only
パッケージを使用して、セッション管理ロジックがサーバーでのみ実行されるようにします。
ヒント:
- ペイロードには、ユーザーID、ロールなど、後続のリクエストで使用される最小限の一意のユーザーデータを含める必要があります。電話番号、メールアドレス、クレジットカード情報などの個人を特定できる情報や、パスワードなどの機密データを含めるべきではありません。
3. クッキーの設定(推奨オプション)
セッションをクッキーに保存するには、Next.jsのcookies
APIを使用します。クッキーはサーバーで設定し、推奨オプションを含める必要があります:
- HttpOnly: クライアントサイドJavaScriptがクッキーにアクセスできないようにします
- Secure: クッキーを送信するためにhttpsを使用します
- SameSite: クロスサイトリクエストでクッキーを送信できるかどうかを指定します
- Max-AgeまたはExpires: 一定期間後にクッキーを削除します
- Path: クッキーのURLパスを定義します
各オプションの詳細については、MDNを参照してください。
サーバーアクションでcreateSession()
関数を呼び出し、redirect()
APIを使用してユーザーを適切なページにリダイレクトできます:
ヒント:
- クッキーはクライアントサイドでの改ざんを防ぐためにサーバーで設定する必要があります
- 🎥 視聴: Next.jsでのステートレスセッションと認証についてさらに学ぶ → YouTube (11分)
セッションの更新(またはリフレッシュ)
セッションの有効期限を延長することもできます。これは、ユーザーがアプリケーションに再度アクセスした後もログイン状態を維持するのに役立ちます。例:
ヒント: 認証ライブラリがリフレッシュトークンをサポートしているか確認してください。リフレッシュトークンを使用してユーザーのセッションを延長できます。
セッションの削除
セッションを削除するには、クッキーを削除します:
その後、deleteSession()
関数をアプリケーション内で再利用できます。例えば、ログアウト時に:
データベースセッション
データベースセッションを作成・管理するには、以下の手順に従います:
- セッションとデータを保存するためのテーブルをデータベースに作成(または認証ライブラリがこれを処理しているか確認)
- セッションの挿入、更新、削除機能を実装
- セッションIDを暗号化してユーザーのブラウザに保存し、データベースとクッキーを同期させる(これはオプションですが、ミドルウェアでの楽観的な認証チェックに推奨)
例:
ヒント:
- 高速なアクセスのため、セッションの存続期間中にサーバーキャッシュを追加することを検討できます。また、セッションデータをプライマリデータベースに保持し、データリクエストを結合してクエリ数を減らすこともできます。
- 高度なユースケース(ユーザーの最終ログイン時間の追跡、アクティブなデバイス数の管理、全デバイスからのログアウト機能の提供など)には、データベースセッションを使用することを選択できます。
セッション管理を実装した後、アプリケーション内でユーザーがアクセス・実行できる内容を制御する認可ロジックを追加する必要があります。詳細については認可セクションに進んでください。
認可
ユーザーが認証されセッションが作成されたら、アプリケーション内でユーザーがアクセス・実行できる内容を制御する認可を実装できます。
認可チェックには主に2つのタイプがあります:
- 楽観的チェック: クッキーに保存されたセッションデータを使用して、ユーザーがルートにアクセスしたりアクションを実行したりする権限があるかどうかを確認します。これらのチェックは、UI要素の表示/非表示や、権限やロールに基づくユーザーのリダイレクトなど、迅速な操作に有用です。
- 安全なチェック: データベースに保存されたセッションデータを使用して、ユーザーがルートにアクセスしたりアクションを実行したりする権限があるかどうかを確認します。これらのチェックはより安全で、機密データへのアクセスやアクションを必要とする操作に使用されます。
どちらの場合も、以下を推奨します:
- 認可ロジックを一元化するためのデータアクセスレイヤーの作成
- 必要なデータのみを返すデータ転送オブジェクト(DTO)の使用
- オプションでミドルウェアを使用して楽観的チェックを実行
ミドルウェアによる楽観的チェック(オプション)
ミドルウェアを使用して、権限に基づいてユーザーをリダイレクトしたい場合があります:
- 楽観的チェックを実行するため。ミドルウェアはすべてのルートで実行されるため、リダイレクトロジックを一元化し、未承認ユーザーを事前にフィルタリングする良い方法です。
- ユーザー間でデータを共有する静的ルート(例: ペイウォールの背後にあるコンテンツ)を保護するため。
ただし、ミドルウェアはプリフェッチされたルートを含むすべてのルートで実行されるため、パフォーマンスの問題を防ぐために、クッキーからのセッション読み取り(楽観的チェック)のみを行い、データベースチェックは避けることが重要です。
例:
ミドルウェアは初期チェックに有用ですが、データ保護の唯一の防衛線として使用すべきではありません。セキュリティチェックの大部分は、データソースにできるだけ近い場所で実行する必要があります。詳細についてはデータアクセスレイヤーを参照してください。
ヒント:
- ミドルウェアでは、
req.cookies.get('session').value
を使用してクッキーを読み取ることもできます。- ミドルウェアはEdge Runtimeを使用します。認証ライブラリとセッション管理ライブラリが互換性があるか確認してください。
- ミドルウェアで実行するルートを指定するために
matcher
プロパティを使用できます。ただし、認証のためには、ミドルウェアがすべてのルートで実行されることを推奨します。
データアクセスレイヤー(DAL)の作成
データリクエストと認可ロジックを一元化するためにDALを作成することを推奨します。
DALには、ユーザーがアプリケーションとやり取りする際にユーザーのセッションを検証する関数を含める必要があります。少なくとも、この関数はセッションが有効かどうかを確認し、リダイレクトまたはさらなるリクエストに必要なユーザー情報を返す必要があります。
例えば、DAL用に別のファイルを作成し、verifySession()
関数を含めます。次に、Reactのcache APIを使用して、Reactのレンダーパス中に関数の戻り値をメモ化します:
その後、データリクエスト、サーバーアクション、ルートハンドラーで verifySession()
関数を呼び出すことができます:
ヒント:
- DALは、リクエスト時にフェッチされるデータを保護するために使用できます。ただし、ユーザー間でデータを共有する静的ルートの場合、データはビルド時にフェッチされ、リクエスト時にはフェッチされません。静的ルートを保護するにはミドルウェアを使用してください。
- 安全なチェックの場合、セッションIDをデータベースと比較してセッションが有効かどうかを確認できます。Reactのcache関数を使用して、レンダーパス中のデータベースへの不要な重複リクエストを回避します。
- 関連するデータリクエストを、任意のメソッドの前に
verifySession()
を実行するJavaScriptクラスに統合することもできます。
データ転送オブジェクト (DTO) の使用
データを取得する際は、アプリケーションで使用する必要なデータのみを返し、オブジェクト全体を返さないことを推奨します。例えば、ユーザーデータを取得する場合、パスワードや電話番号などが含まれるユーザーオブジェクト全体ではなく、ユーザーIDと名前のみを返すことが考えられます。
ただし、返されるデータ構造を制御できない場合や、クライアントにオブジェクト全体が渡されるのを防ぎたいチームで作業している場合は、クライアントに公開しても安全なフィールドを指定するなどの戦略を使用できます。
データアクセス層 (DAL) でデータリクエストと認可ロジックを集中化し、DTOを使用することで、すべてのデータリクエストが安全で一貫性を持つようになり、アプリケーションのスケールに伴うメンテナンス、監査、デバッグが容易になります。
知っておくと良いこと:
- DTOを定義する方法はいくつかあります。
toJSON()
を使用する方法、上記の例のような個別の関数、JSクラスなどです。これらはReactやNext.jsの機能ではなくJavaScriptのパターンなので、アプリケーションに最適なパターンを見つけるために調査を行うことを推奨します。- セキュリティのベストプラクティスについては Next.jsのセキュリティ記事 で詳しく学べます。
サーバーコンポーネント
サーバーコンポーネント での認証チェックは、ロールベースのアクセス制御に有用です。例えば、ユーザーのロールに基づいてコンポーネントを条件付きでレンダリングする場合:
この例では、DALから verifySession()
関数を使用して 'admin'、'user'、および未認証のロールをチェックしています。このパターンにより、各ユーザーは自身のロールに適したコンポーネントのみと対話します。
レイアウトと認証チェック
部分レンダリング のため、レイアウト でチェックを行う際は注意が必要です。これらはナビゲーション時に再レンダリングされないため、ルート変更ごとにユーザーセッションがチェックされません。
代わりに、データソースに近い場所や条件付きでレンダリングされるコンポーネントでチェックを行うべきです。
例えば、ユーザーデータを取得しナビにユーザー画像を表示する共有レイアウトを考えます。レイアウトで認証チェックを行うのではなく、レイアウトでユーザーデータ (getUser()
) を取得し、DALで認証チェックを行うべきです。
これにより、アプリケーション内で getUser()
が呼び出される場所では常に認証チェックが行われ、開発者がデータへのアクセス権限をチェックするのを忘れるのを防ぎます。
知っておくと良いこと:
- SPAでは、ユーザーが認証されていない場合にレイアウトやトップレベルのコンポーネントで
return null
とするパターンが一般的です。このパターンは 推奨されません。Next.jsアプリケーションには複数のエントリーポイントがあり、ネストされたルートセグメントやサーバーアクションへのアクセスを防げないためです。
サーバーアクション
サーバーアクション は、公開APIエンドポイントと同じセキュリティ考慮事項で扱い、ユーザーが変更を実行できるかどうかを確認してください。
以下の例では、アクションを進める前にユーザーのロールをチェックしています:
ルートハンドラー
ルートハンドラー は、公開APIエンドポイントと同じセキュリティ考慮事項で扱い、ユーザーがルートハンドラーにアクセスできるかどうかを確認してください。
例:
上記の例は、2段階のセキュリティチェックを持つルートハンドラーを示しています。最初にアクティブなセッションをチェックし、次にログインしているユーザーが 'admin' かどうかを確認します。
コンテキストプロバイダー
認証にコンテキストプロバイダーを使用するのは、インターリービング により機能します。ただし、Reactの context
はサーバーコンポーネントではサポートされていないため、クライアントコンポーネントにのみ適用可能です。
これは機能しますが、子のサーバーコンポーネントは最初にサーバーでレンダリングされ、コンテキストプロバイダーのセッションデータにはアクセスできません:
クライアントコンポーネントでセッションデータが必要な場合(例えばクライアントサイドのデータフェッチング)、Reactの taintUniqueValue
APIを使用して、機密性の高いセッションデータがクライアントに公開されないようにします。
リソース
Next.jsでの認証について学んだので、安全な認証とセッション管理を実装するのに役立つNext.js互換のライブラリとリソースを紹介します:
認証ライブラリ
セッション管理ライブラリ
さらに学ぶ
認証とセキュリティについてさらに学ぶには、以下のリソースを参照してください: