言語を切り替える
テーマを切り替える

NextAuth.js 入門チュートリアル:Credentials ログイン設定とセッション管理完全ガイド

はじめに

NextAuth.js の公式ドキュメントを開いたあの日、私は画面いっぱいの設定項目を前に30分間呆然としていました。Provider、Session、Adapter、JWT、Callbacks…単語は知っているけれど、それらがどう繋がるのかさっぱり分かりません。一番腹立たしいのは、ドキュメントに「デフォルトで JWT を使用」と書いてあるのに、次の段落では「データベース使用時は自動的に Session に切り替わる」とあることです。結局どっちを使えばいいの?

正直、Clerk に逃げてしまおうかと本気で思いました。Clerk は速くて簡単ですが、月間アクティブユーザー数が10,000を超えると有料になりますし、カスタマイズできない部分も多いです。NextAuth.js は取っ付きにくいですが、完全無料で完全にコントロールできます。

この記事では、すべての設定項目を羅列するような(拷問のような)ことはしません。代わりに、最も一般的な Credentials ログイン(ユーザー名とパスワード)、会话管理データベース統合という核心的な問題に焦点を当てます。これさえ理解できれば、NextAuth.js は怖くありません。

NextAuth.js のコアコンセプトを理解する

NextAuth.js は何をしているのか?

一言で言えば、NextAuth.js は「誰がログインしたか」と「ログイン状態をどう保存するか」を管理する認証ミドルウェアです。どんなデータベースを使っているか、UI がどうなっているかは気にせず、ユーザーの本人確認とログイン状態の記憶だけを担当します。

Clerk や Supabase Auth との違いは?

  • Clerk: 美しいログイン UI やユーザー管理画面があり、30分で導入完了。ただし有料(10,000 MAU以上)。
  • Supabase Auth: Supabase データベースを使うなら、認証機能はほぼ無料でついてきます。統合は非常にスムーズ。
  • NextAuth.js: 完全無料・オープンソース。ただしログイン画面、ユーザー登録、データベースロジックは自分で書く必要があります。

2025年のトレンドは興味深いです。NextAuth.js は依然として多くの人に使われていますが、Clerk のような「即座に使える」ソリューションが急速に市場を奪っています。数日かけて認証コードを書くより、コア機能に時間をかける方が合理的だという判断でしょう。とはいえ、個人プロジェクトや完全なコントロールが必要な場合は、NextAuth.js を学ぶ価値は十分にあります。

3つの必須概念

1. Provider(プロバイダー):どうやってログインするか?

ログイン方法のことです。NextAuth.js は50種類以上をサポートしています。

  • OAuth プロバイダー: Google、GitHub、Facebook など。クリック一発でログインでき、パスワード管理は不要。
  • Credentials プロバイダー: ユーザー名+パスワード。最も伝統的な方法で、この記事の重点です。

注意点があります。Credentials プロバイダーは最も柔軟ですが、最もコードを書く必要があります。公式でさえ推奨していないほどです。なぜなら、パスワードの暗号化、総当たり攻撃への対策、セッション管理などのセキュリティリスクをすべて自分で負わなければならないからです。

2. Session(セッション):ログイン後どうやってユーザーを覚えるか?

一度ログインしたら、リクエストのたびにパスワードを入力させたくないですよね? Session は「ログイン状態を記憶する」仕組みです。2つの方式があります。

  • JWT Session: ログイン情報を暗号化して Cookie に詰め込みます。サーバーは何もしなくて済みます。
  • Database Session: Cookie には ID だけを入れ、本当のログイン情報はデータベースに保存します。

どちらを選ぶかが、NextAuth.js 初学者が最も混乱するポイントです。次節で詳しく解説します。

3. Adapter(アダプター):ユーザーデータをどこに保存するか?

ユーザー情報(メール、登録日時など)をデータベースに保存したい場合、Adapter が必要です。NextAuth.js は Prisma、MongoDB、MySQL など様々なデータベースをサポートしています。

重要なのは、Credentials プロバイダーは自動的にユーザー情報をデータベースに保存しないということです。公式ドキュメントにも明記されていますが、Credentials を使う場合、ユーザーアカウント管理は自分でやる必要があります。NextAuth.js はログイン検証だけで、登録や保存は関知しません。

JWT vs Session:どっちを使うべき?

これは核心的な質問です。私も十数記事読みましたが決断できませんでした。本質的な違いを理解するまでは。

JWT Session:パスポート方式

海外旅行に行く時、パスポートには写真、名前、有効期限が印刷されています。入国審査ではパスポートを見るだけでよく、システム照会は不要です。JWT も同じで、ログイン後にサーバーは暗号化されたトークン(パスポートのようなもの)を生成し、userId や email などの情報を含めてブラウザの Cookie に保存します。

メリット:

  • 速い。DB を引く必要がなく、トークンを復号すればユーザーが分かります。
  • 安い。セッションを保存する DB が不要で、Serverless デプロイに最適。
  • 拡張性。ユーザーが増えてもセッションテーブルが爆発する心配がありません。

デメリット:

  • ユーザーを強制ログアウトできない。アカウント乗っ取られたから特定のログインを無効化したい? 無理です。トークンが期限切れになるまで有効です(ブラックリストを作れば可能ですが、それなら DB が必要です)。
  • 複数端末ログイン制限ができない。「同時に3台まで」といった制限は不可能です。
  • トークン期限切れまで情報を更新できない。トークンに役割(ロール)を入れていて、後でロールが変わっても、トークンが更新されるまでユーザーは古いロールのままです。

Database Session:ホテルのカードキー方式

ホテルでカードキーを受け取りますが、それには部屋番号しか入っていません。あなたの詳細情報(パスポート、利用履歴)はホテルのシステムにあります。カードをかざすたびに、システムは部屋番号をチェックして入室権限を確認します。Database Session も同じで、Cookie には Session ID だけが入っており、本当のユーザー情報は DB にあります。

メリット:

  • いつでもログインを無効化できる。「全デバイスからログアウト」? DB のセッションレコードを消すだけで完了。
  • ログインデバイス数を制限できる。
  • ユーザー情報をリアルタイム更新できる(権限が変われば次のリクエストで即反映)。

デメリット:

  • 遅い。リクエストごとに DB を引く必要があります。
  • セッションテーブルの管理が必要(作成、期限切れ削除)。
  • ユーザーが増えると DB 負荷が上がります。

判定ツリー(重要)

「で、どっちを選べばいいの?」というあなたへ。私のアドバイス:

あなたのアプリに「ユーザーの再ログインを強制する」機能は必要ですか?(例:パスワード変更、アカウント凍結)
  ├─ はい → Database Session を使う
  └─ いいえ → 次へ

データベースを節約したい、または Serverless でデプロイしたいですか?
  ├─ はい → JWT を使う
  └─ いいえ → 次へ

あなたのアプリは個人プロジェクト/MVPで、速くリリースしたいですか?
  ├─ はい → JWT を使う(簡単、手間いらず)
  └─ いいえ → Database Session を使う(企業アプリ向けで堅実)

私自身のプロジェクトでは、最初は JWT を使っていましたが、後に「ユーザー管理画面」を追加してユーザーをキックアウトする必要が出てきたため、Database Session に切り替えました。切り替えコストは結構高いので、最初に決めておくことをお勧めします。

特殊ケース:Credentials + Database Session

Credentials プロバイダーを使いつつ Database Session も使いたい場合、大きな落とし穴があります。公式ドキュメントでは「サポートしてない」と言っているのです。

具体的には、OAuth プロバイダー(Google、GitHub)は Database Session をシームレスに使えますが、Credentials はダメです。理由は、NextAuth.js は Credentials が柔軟すぎて自動的にセッションレコードを作成できないと考えているからです。

解決策はありますが、手動でコードを書き、signIn callback 内で自分でセッションを作成する必要があります。GitHub に多くの議論(例:この issue)があり、参考になるソリューションもあります。ただ正直なところ、あなたが初心者のなら、JWT を使うか、OAuth プロバイダーに切り替えることをお勧めします。トラブルの元です。

Credentials プロバイダー完全設定

理論は終わりました。コードを書きましょう。3つのバージョン(シンプルから完全版まで)を示しますので、段階に合わせて選んでください。

基本設定:最小実行可能バージョン

依存関係をインストール:

npm install next-auth

ファイルを作成します。Next.js 13+ App Router の場合、パスは app/api/auth/[...nextauth]/route.ts です。Pages Router なら pages/api/auth/[...nextauth].js です。ここでは App Router で例示します。

app/api/auth/[…nextauth]/route.ts:

import NextAuth from "next-auth"
import CredentialsProvider from "next-auth/providers/credentials"

const handler = NextAuth({
  providers: [
    CredentialsProvider({
      name: 'Credentials',
      credentials: {
        email: { label: "メール", type: "email" },
        password: { label: "パスワード", type: "password" }
      },
      async authorize(credentials) {
        // テスト用にユーザーをハードコード
        if (credentials?.email === "test@example.com" &&
            credentials?.password === "123456") {
          return {
            id: "1",
            name: "テストユーザー",
            email: "test@example.com"
          }
        }
        return null  // ログイン失敗
      }
    })
  ],
  session: {
    strategy: "jwt"  // JWT session を使用
  },
  pages: {
    signIn: '/login'  // カスタムログインページ(オプション)
  }
})

export { handler as GET, handler as POST }

環境変数 .env.local:

NEXTAUTH_SECRET=your-super-secret-key-change-this
NEXTAUTH_URL=http://localhost:3000

重要ポイント:

  • NEXTAUTH_SECRET: トークンの暗号化に使用。本番環境では必須、ローカルでも設定推奨。生成方法: openssl rand -base64 32
  • authorize 関数: 本人確認のコアロジック。ユーザーオブジェクトを返せば成功、null なら失敗。

このバージョンは動きますが、ユーザーデータがハードコードされており実用的ではありません。次はデータベースに接続します。

重要な設定項目の詳細

完全なコード例に行く前に、最も紛らわしい設定をいくつか説明しておきます。

1. session.strategy: “jwt” か “database” か?

前述の通り、デフォルトは “jwt” です。Adapter(DB 接続)を使うと自動的に “database” に切り替わります。しかし、Credentials プロバイダー + JWT を使いたい場合は、明示的に strategy: "jwt" と書かないとエラーになることがあります。

2. callbacks: セッションにカスタムフィールドを追加するには?

デフォルトでは、useSession が返すユーザー情報は nameemailimage だけです。userIdrole を追加したい場合はどうすれば?

callbacks を使います:

callbacks: {
  async jwt({ token, user }) {
    // user はログイン時のみ値が入る
    if (user) {
      token.userId = user.id  // userId を token に追加
    }
    return token
  },
  async session({ session, token }) {
    // token の userId を session に入れる
    session.user.userId = token.userId
    return session
  }
}

これでフロントエンドで const { data: session } = useSession() した時、session.user.userId が取得できます。

3. pages: カスタムログインページ

NextAuth.js には組み込みの(ダサい)ログインページ(/api/auth/signin)があります。独自のログイン UI を使いたいなら pages: { signIn: '/login' } を設定します。

あなたのログインページでは以下を呼び出します:

import { signIn } from "next-auth/react"

const handleSubmit = async (e) => {
  e.preventDefault()
  const result = await signIn('credentials', {
    redirect: false,
    email,
    password
  })

  if (result?.error) {
    // ログイン失敗
  } else {
    // ログイン成功、ジャンプ
  }
}

完全な例:登録+ログイン+セッション管理

では、リアルに使えるバージョンです。Prisma + PostgreSQL を想定します。

1. ユーザーテーブル作成

prisma/schema.prisma:

model User {
  id        String   @id @default(cuid())
  email     String   @unique
  password  String
  name      String?
  createdAt DateTime @default(now())
}

npx prisma migrate dev でテーブル作成。

2. 登録 API

app/api/register/route.ts:

import { NextResponse } from "next/server"
import bcrypt from "bcryptjs"
import { prisma } from "@/lib/prisma"  // prisma client があると仮定

export async function POST(req: Request) {
  try {
    const { email, password, name } = await req.json()

    // ユーザー重複チェック
    const existingUser = await prisma.user.findUnique({
      where: { email }
    })

    if (existingUser) {
      return NextResponse.json(
        { error: "このメールアドレスは既に登録されています" },
        { status: 400 }
      )
    }

    // パスワード暗号化(重要!)
    const hashedPassword = await bcrypt.hash(password, 10)

    // ユーザー作成
    const user = await prisma.user.create({
      data: {
        email,
        password: hashedPassword,
        name
      }
    })

    return NextResponse.json({
      user: {
        id: user.id,
        email: user.email,
        name: user.name
      }
    })
  } catch (error) {
    return NextResponse.json(
      { error: "登録失敗" },
      { status: 500 }
    )
  }
}

重要: パスワードは必ず暗号化! bcryptargon2 を使い、平文で保存しないでください。

3. NextAuth 設定(DB 接続)

app/api/auth/[...nextauth]/route.ts:

import NextAuth from "next-auth"
import CredentialsProvider from "next-auth/providers/credentials"
import bcrypt from "bcryptjs"
import { prisma } from "@/lib/prisma"

const handler = NextAuth({
  providers: [
    CredentialsProvider({
      credentials: {
        email: { label: "メール", type: "email" },
        password: { label: "パスワード", type: "password" }
      },
      async authorize(credentials) {
        if (!credentials?.email || !credentials?.password) {
          return null
        }

        // DB からユーザー検索
        const user = await prisma.user.findUnique({
          where: { email: credentials.email }
        })

        if (!user) {
          return null  // ユーザー不在
        }

        // パスワード検証
        const isValid = await bcrypt.compare(
          credentials.password,
          user.password
        )

        if (!isValid) {
          return null  // パスワード間違い
        }

        // ユーザー情報を返す(パスワードは含めない!)
        return {
          id: user.id,
          email: user.email,
          name: user.name
        }
      }
    })
  ],
  session: {
    strategy: "jwt",
    maxAge: 30 * 24 * 60 * 60  // 30日
  },
  callbacks: {
    async jwt({ token, user }) {
      if (user) {
        token.userId = user.id
      }
      return token
    },
    async session({ session, token }) {
      session.user.userId = token.userId as string
      return session
    }
  },
  pages: {
    signIn: '/login'
  }
})

export { handler as GET, handler as POST }

4. フロントエンドでのセッション使用

サーバーコンポーネント (Server Component):

import { getServerSession } from "next-auth"

export default async function ProfilePage() {
  const session = await getServerSession()

  if (!session) {
    redirect('/login')
  }

  return <div>ようこそ, {session.user.name}</div>
}

クライアントコンポーネント (Client Component):

'use client'
import { useSession } from "next-auth/react"

export default function Dashboard() {
  const { data: session, status } = useSession()

  if (status === "loading") {
    return <div>読み込み中...</div>
  }

  if (!session) {
    return <div>ログインしてください</div>
  }

  return <div>あなたのユーザーID: {session.user.userId}</div>
}

注意:

  • サーバー側は getServerSession()
  • クライアント側は useSession()
  • クライアントコンポーネントの外側(通常は layout)を <SessionProvider> でラップする必要があります。

セッション管理戦略とよくある問題

JWT セッションの正しい使い方

JWT を選んだなら、うまく使いこなしましょう。いくつかのポイント:

1. JWT に追加情報を保存(userId, role など)

callbacks の例で示しましたが、再確認:jwt callback はトークンへの追加、session callback はトークンからセッションへの転記に使います。

ロール(役割)を保存したい場合:

callbacks: {
  async jwt({ token, user }) {
    if (user) {
      token.userId = user.id
      token.role = user.role  // DB に role フィールドがあると仮定
    }
    return token
  },
  async session({ session, token }) {
    session.user.userId = token.userId as string
    session.user.role = token.role as string
    return session
  }
}

2. トークン有効期限の設定

デフォルトは30日ですが、変更可能です:

session: {
  strategy: "jwt",
  maxAge: 7 * 24 * 60 * 60  // 7日
}

落とし穴:ユーザーがブラウザを閉じて再度開いても、トークンは残っています(手動ログアウトしない限り)。「ブラウザを閉じたらログアウト」を実現したい場合、フロントエンドで処理する必要があります。バックエンドの JWT だけでは不可能です。

3. JWT 最大の制限:能動的な無効化ができない

これが JWT の頭痛の種です。アカウントが乗っ取られたことに気づき、そのユーザーをすぐにログアウトさせたい? 残念ながらできません。トークンを持っている人は、期限が切れるまでアクセス可能です。

回避策:

  • トークン有効期限を短くする(例:1時間)。UX は犠牲になりますが、安全性は上がります。
  • トークンブラックリストを管理する(ただし DB が必要になり、JWT の利点が薄れます)。
  • Database Session を使う(これなら一発解決です)。

Database Session の実装(Credentials プロバイダー含む)

始めから Database Session を選んだ場合、OAuth プロバイダー(Google, GitHub)を使うなら設定はもっと簡単です。

Adapter をインストール:

npm install @next-auth/prisma-adapter

設定:

import { PrismaAdapter } from "@next-auth/prisma-adapter"
import { prisma } from "@/lib/prisma"

const handler = NextAuth({
  adapter: PrismaAdapter(prisma),
  providers: [
    GoogleProvider({
      clientId: process.env.GOOGLE_CLIENT_ID!,
      clientSecret: process.env.GOOGLE_CLIENT_SECRET!
    })
  ]
  // strategy は自動的に "database" になるので設定不要
})

データベースには User, Session, Account 等のテーブルが自動作成されます。

しかし、Credentials プロバイダーを使う場合は面倒です。公式ドキュメントには 「Credentials provider は database session をサポートしていません」 と明記されています。

ネット上には解決策がいろいろあり、主なアプローチは signIn callback で手動でセッションレコードを作成することです。初心者がこれをやるのはお勧めしません。エラーになりやすいからです。どうしても Credentials + Database Session が必要なら、以下の GitHub 議論を見てください:

あるいは、Clerk や Supabase Auth への乗り換えを検討してください。これらはこの組み合わせをネイティブにサポートしています。

最もハマりやすい5つの落とし穴

これらは私が全部踏んだ落とし穴です。時間を無駄にしないでください。

1. NEXTAUTH_SECRET の設定忘れで本番エラー

ローカル開発時は NEXTAUTH_SECRET がなくても警告だけで動きますが、Vercel や Railway にデプロイしてこの環境変数がないと、即座に 500 エラーになります。

生成方法:openssl rand -base64 32。デプロイプラットフォームの環境変数に追加してください。

2. Credentials プロバイダーはデフォルトで database session が使えない

しつこいようですが再確認:Adapter を設定しつつ Credentials を使うとエラーになります。session: { strategy: "jwt" } を明示的に設定するか、手動でセッション作成ロジックを実装する必要があります。

3. useSession はサーバーコンポーネントで使えない

Next.js 13+ App Router はデフォルトで Server Component です。サーバーコンポーネント内で const session = useSession() と書くとエラーになります。hooks はクライアントでしか使えません。

サーバー側では getServerSession() を使います:

import { getServerSession } from "next-auth"

const session = await getServerSession()

クライアント側では 'use client' ディレクティブを追加してから useSession() を使います。

4. Cookie のクロスオリジン問題

開発環境 localhost:3000、本番環境 example.com で Cookie のドメインが異なると、ログイン状態が失われることがあります。

解決:本番環境では NEXTAUTH_URL 環境変数を正しいドメインに設定してください。ハードコードで localhost にしないように。

5. JWEDecryptionFailed エラー

エラー:JWEDecryptionFailed: decryption operation failed

原因:NEXTAUTH_SECRET を変更したのに、ブラウザに古いトークンが残っている。古いトークンを新しいシークレットで復号できずエラーになります。

解決:ブラウザの Cookie をクリアするか、再ログインしてください。

おまけ:Middleware でルート保護

特定のページをログイン必須にしたい場合、Middleware を使います。

middleware.ts:

export { default } from "next-auth/middleware"

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

これで /dashboard/profile 以下の全ページでログイン状態がチェックされ、未ログインなら自動的にログインページに飛びます。

実際のプロジェクトへの提案と進歩ロードマップ

どのプランを選ぶべきか?意思決定のアドバイス

長くなりましたが、最後に決定をお手伝いします。

シナリオ1: 個人プロジェクト/MVP/ブログ

  • 推奨: NextAuth.js + JWT + Credentials
  • 理由: 完全無料、設定簡単、セッションテーブル管理不要
  • 欠点: 後で「キックアウト」機能を追加する際の移行コストが高い

シナリオ2: 企業アプリ/SaaS製品(予算あり)

  • 推奨: Clerk
  • 理由: 30分で完了、美しいUI、ユーザー管理機能完備、開発時間を40-80時間節約
  • 欠点: 10,000 MAU を超えると有料、カスタマイズに制限あり
  • 補足: Supabase を使うなら、Supabase Auth も良い(無料枠 50,000 MAU)

シナリオ3: 企業アプリ(予算なし/完全制御が必要)

  • 推奨: NextAuth.js + Database Session + OAuth プロバイダー(Google/GitHub)
  • 理由: 完全無料、全機能あり、キックアウト可能
  • 欠点: ログイン UI や DB 管理を自分でやる必要がある

シナリオ4: 既存ユーザーシステムがあり、認証層だけ追加したい

  • 推奨: NextAuth.js + Credentials + JWT
  • 理由: 柔軟、既存 DB 構造に侵入しない
  • 注意: セキュリティ対策(パスワード暗号化、総当たり防止)は自前で

私自身の経験:最初のプロジェクトは JWT でしたが、半年後にユーザー管理機能が必要になり、Database Session への移行に2日かかりました。2つ目のプロジェクトは最初から要件を見極め、Database Session を選択したので手間が省けました。

学習ロードマップ

Credentials ログインができるようになったら、次はこれを学びましょう:

1. OAuth プロバイダー(より簡単で推奨)

  • Google、GitHub ログインは Credentials よりずっと簡単です
  • パスワード暗号化や登録フローを気にする必要がありません
  • ユーザー体験も良い(ワンクリックログイン)

2. ミドルウェア (Middleware): ルート保護

  • さきほど示しましたが、1行でディレクトリ全体を保護できます
  • 各ページでセッションチェックするより遥かに便利

3. マルチロール権限管理 (RBAC)

  • セッションに role を保存
  • role に基づいてコンテンツや権限を出し分ける
  • 進んだ内容として CASL ライブラリ(詳細な権限制御)を学ぶ

4. メール認証とパスワードリセット

  • NextAuth.js の Email Provider(マジックリンクログイン)
  • パスワード忘れ機能の自作(リセットリンク送信)

参考リソース

公式ドキュメント(必読):

実用チュートリアル:

GitHub Discussions(困った時に検索):

競合比較(選択の助けに):

結論

いろいろ言いましたが、NextAuth.js の核心は3つの決定です:

  1. どのログイン方式か? Credentials か OAuth か? ほとんどの場合 OAuth(Google/GitHub)が簡単です。
  2. セッションをどう保存するか? JWT か Database か? 個人なら JWT、企業なら Database。
  3. ユーザー検証方法は? Credentials は自分で書き、OAuth はプロバイダー任せ。

私のアドバイス:まずは最小構成のサンプル(本文の「最小実行可能バージョン」)を動かし、ログインできるようになったら徐々に機能を追加してください。最初から全設定を理解しようとすると挫折します。

NextAuth.js は確かに学習曲線がありますが、覚えれば認証フローを完全に掌握できます。速さなら Clerk、コストと学習なら NextAuth.js。

最後に、コメント欄であなたが遭遇した問題を教えてください。設定のどこで詰まったか? JWT と Session で迷っているか?

推奨読書:

  • 次回は「Next.js Middleware 完全ガイド」を書く予定です。ルート保護や A/B テストなどのシナリオを含みます。

NextAuth.js Credentials ログイン設定完全フロー

インストールからユーザー名パスワードログインの実装、セッション管理までの完全な手順

⏱️ Estimated time: 2 hr

  1. 1

    Step1: NextAuth.js のインストールと初期化

    依存関係のインストール:
    • npm install next-auth
    • app/api/auth/[...nextauth]/route.ts を作成

    基本設定:
    • NEXTAUTH_URL を設定(ローカル:http://localhost:3000)
    • NEXTAUTH_SECRET を設定(ランダム文字列を生成)
    • providers 配列を設定
  2. 2

    Step2: Credentials Provider の設定

    検証ロジックの実装:
    1. CredentialsProvider の authorize 関数内でユーザーを検証
    2. DB からユーザーを検索(またはハードコードでテスト)
    3. パスワードを検証(bcrypt 等を使用)
    4. ユーザーオブジェクト(id, name, email 等)を返す

    注意:
    • authorize 関数はユーザーオブジェクトか null を返す必要がある
    • 返されたオブジェクトは session に保存される
    • パスワード検証はサーバー側で行うべき
  3. 3

    Step3: セッション戦略の選択(JWT または Session)

    JWT 戦略(デフォルト):
    • ステートレスアプリ向け
    • セッション情報は JWT トークンに保存
    • DB 不要
    • 設定:session: { strategy: 'jwt' }

    Session 戦略(要 DB):
    • ログイン取り消しが必要なアプリ向け
    • セッション情報は DB に保存
    • Adapter 設定が必要(Prisma, MongoDB 等)
    • 設定:session: { strategy: 'database' }
  4. 4

    Step4: Callbacks でフローをカスタマイズ

    よく使う Callbacks:
    • signIn:ログイン許可の制御
    • jwt:JWT トークン内容のカスタマイズ(JWT 戦略)
    • session:session 内容のカスタマイズ

    例:
    callbacks: {
    async jwt({ token, user }) {
    if (user) token.role = user.role
    return token
    },
    async session({ session, token }) {
    session.user.role = token.role
    return session
    }
    }
  5. 5

    Step5: ログインページとコンポーネントの作成

    NextAuth.js API の使用:
    • signIn('credentials', { username, password }):ログイン実行
    • signOut():ログアウト
    • useSession():現在のセッション取得
    • SessionProvider:アプリをラップしてセッションコンテキストを提供

    例:
    const { data: session } = useSession()
    if (session) {
    return <div>ログイン中:{session.user.name}</div>
    }
  6. 6

    Step6: テストとデバッグ

    テストポイント:
    • 正しいパスワードでログインできるか
    • 間違ったパスワードが拒否されるか
    • セッションが維持されるか
    • ログアウトでセッションが消えるか

    デバッグ方法:
    • ブラウザコンソールのエラー確認
    • サーバーログの確認
    • NextAuth.js デバッグモードの使用
    • 環境変数の再確認

FAQ

NextAuth.js と Clerk、Supabase Auth の違いは?
NextAuth.js:
• 完全無料・オープンソースのセルフホスト型
• ログイン UI やユーザー管理は自作が必要
• 完全なコントロールが可能

Clerk:
• 完全な UI と管理画面を提供
• 10,000 MAU を超えると有料

Supabase Auth:
• Supabase データベースを使うプロジェクトに最適
• 統合が簡単だがデータベースに縛られる
JWT と Session どちらを選ぶべき?
JWT はステートレスアプリ、個人プロジェクトに適しており、データベース不要ですが、個別のセッション無効化ができません。Session は企業アプリ、ログイン取り消しが必要なシナリオに適しており、データベース Adapter が必要ですが、セッションを精密に制御できます。
Credentials ログインは安全ですか?
安全ですが、以下の点に注意が必要です:
1) パスワードは必ず暗号化して保存(bcrypt 等)
2) 検証ロジックは必ずサーバー側で行う
3) HTTPS 通信を使用する
4) パスワード強度要件を実装する
5) 総当たり攻撃防止のキャプチャ等を検討する
ログインページをカスタマイズするには?
NextAuth 設定の pages オプションを使用します:pages: { signIn: '/auth/login' }。

その後、カスタムログインページを作成し、signIn('credentials', { username, password }) を使ってログインをトリガーします。

NextAuth.js の API のみを使用し、UI は完全に自由に作れます。
現在のログインユーザーを取得するには?
クライアント側では useSession() hook を使用:
const { data: session } = useSession()

サーバー側では getServerSession() を使用:
const session = await getServerSession(authOptions)

session オブジェクトにユーザー情報(id, name, email 等)が含まれます。
ロールと権限管理はどう実装しますか?
callbacks 内で JWT または Session の内容をカスタマイズし、role フィールドを追加します。その後、ページや API ルートで session.user.role をチェックし、ロールに基づいてアクセスを許可するか決定します。Middleware でグローバルな権限チェックを行うことも可能です。
NextAuth.js はどのデータベースをサポートしていますか?
NextAuth.js は Adapter を通じて、Prisma(PostgreSQL、MySQL、SQLite 等)、MongoDB、TypeORM、Drizzle ORM など多数のデータベースをサポートしています。Adapter を使用すると自動的に Session 戦略に切り替わり、セッション情報がデータベースに保存されます。
  • ユーザー権限管理に興味があれば、以前書いた「RBAC権限設計の実践」もご覧ください。

8 min read · 公開日: 2025年12月19日 · 更新日: 2026年1月22日

コメント

GitHubアカウントでログインしてコメントできます

関連記事