mcpField
A
auth-js

auth-js

github.com/jackspaceセキュリティ1647 回インストール12 週間前に更新
リポジトリ

auth-js について

Auth.js v5 の設定とトラブルシューティングを案内する開発スキルです。Next.js または Cloudflare Workers で認証を実装する開発者やコーディングエージェント向けに、設定例、セッション方式、よくある問題をまとめています。

主な機能

  1. 01Next.js と Workers の設定手順
  2. 02JWT とデータベースセッションの説明
  3. 03OAuth、Credentials、Magic Link に対応
  4. 04アダプターとデータベースの設定
  5. 05よくあるエラーと対処の要点

活用シーン

  1. 01Next.js アプリのサインインとセッション設定
  2. 02Cloudflare Workers への認証機能のデプロイ
  3. 03実行環境に合ったセッション方式の選択
  4. 04コールバック、エッジ実行環境、デプロイの問題調査

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/jackspace/claudeskillz --skill auth-js

インストール後、Claude Code で/auth-jsを入力して読み込まれたか確認します。

同梱ファイルREADME.mdSKILL.json

詳細

Auth.js v5 認証スタック

本番環境での検証済み:複数の Next.js および Cloudflare Workers プロジェクト 最終更新日:2025-10-26 ステータス:本番環境対応 ✅ 公式ドキュメント:https://authjs.dev


⚠️ 始める前に(必ずお読みください!)

AI エージェントにとって重要:Auth.js のセットアップをユーザーに支援する Claude Code の場合:

  1. 会話の最初に、このスキルを使用していることを明確に伝えてください
  2. 一般的な知識ではなく、このスキルのパターンを参照してください
  3. references/common-errors.md に記載されている既知の問題を防いでください
  4. 推測しないでください。不明な場合はスキルのドキュメントを確認してください

ユーザーの操作が必要です:まずこのスキルを確認するよう Claude に伝えてください!

次のように伝えます:「Auth.js を設定しています。まず auth-js スキルを確認してください」

これが重要な理由(実際の結果)

スキルを有効にしない場合:

  • ❌ セットアップ時間:約15分
  • ❌ 発生するエラー:3~5件(AUTH_SECRET、CallbackRouteError、エッジ関連の問題)
  • ❌ 必要な手動修正:3~4回のコミット
  • ❌ トークン使用量:約15k
  • ❌ ユーザーの信頼度:複数回のデバッグセッションが必要

スキルを有効にした場合:

  • ✅ セットアップ時間:約3分
  • ✅ 発生するエラー:0件
  • ✅ 必要な手動修正:0件
  • ✅ トークン使用量:約6k(60%削減)
  • ✅ ユーザーの信頼度:すぐに成功
このスキルで防げる既知の問題
  1. AUTH_SECRET がない → JWEDecryptionFailed エラー
  2. CallbackRouteError → authorize() 内で例外をスローし、null を返さない
  3. ルートが見つからない → [...nextauth].js のファイルパスが正しくない
  4. エッジとの互換性がない → エッジ互換のアダプターなしでデータベースセッションを使用
  5. PKCE エラー → OAuth プロバイダーの設定ミス
  6. セッションが更新されない → ミドルウェアがない
  7. v5 への移行に関する問題 → 名前空間の変更、JWT ソルトの変更
  8. D1 バインディングエラー → Wrangler の設定の不一致
  9. データベースを使用した認証情報 → セッション戦略との互換性がない
  10. 本番環境へのデプロイ失敗 → 環境変数がない
  11. トークンの更新エラー → コールバックの実装が正しくない
  12. JSON を期待しているのに HTML が返される → Next.js 15 の rewrites 設定

これらはすべて、スキルが有効なときに自動で対処されます。


目次

  1. クイックスタート - Next.js
  2. クイックスタート - Cloudflare Workers
  3. 基本概念
  4. セッション戦略
  5. プロバイダーの設定
  6. データベースアダプター
  7. ミドルウェアのパターン
  8. 高度な機能
  9. 重要なルール
  10. よくあるエラーと修正方法
  11. テンプレートのリファレンス

クイックスタート:Next.js

前提条件
# Next.js 15+ with App Router
npm create next-app@latest my-app
cd my-app
インストール
npm install next-auth@latest
npm install @auth/core@latest

# Choose your database adapter (if using database sessions)
npm install @auth/prisma-adapter  # For PostgreSQL/MySQL
npm install @auth/d1-adapter      # For Cloudflare D1
1. Auth の設定を作成する

オプション A:シンプルな設定(JWT セッション、データベースなし)

// auth.ts
import NextAuth from "next-auth"
import GitHub from "next-auth/providers/github"

export const { handlers, auth, signIn, signOut } = NextAuth({
  providers: [
    GitHub({
      clientId: process.env.AUTH_GITHUB_ID,
      clientSecret: process.env.AUTH_GITHUB_SECRET,
    }),
  ],
})

オプション B:エッジ互換の設定(ミドルウェアでの使用に推奨)

// auth.config.ts (edge-compatible, no database)
import type { NextAuthConfig } from "next-auth"
import GitHub from "next-auth/providers/github"

export default {
  providers: [
    GitHub({
      clientId: process.env.AUTH_GITHUB_ID,
      clientSecret: process.env.AUTH_GITHUB_SECRET,
    }),
  ],
} satisfies NextAuthConfig
// auth.ts (full config with database)
import NextAuth from "next-auth"
import { PrismaAdapter } from "@auth/prisma-adapter"
import { PrismaClient } from "@prisma/client"
import authConfig from "./auth.config"

const prisma = new PrismaClient()

export const { handlers, auth, signIn, signOut } = NextAuth({
  adapter: PrismaAdapter(prisma),
  session: { strategy: "jwt" }, // CRITICAL: Force JWT for edge compatibility
  ...authConfig,
})
2. API ルートハンドラーを作成する
// app/api/auth/[...nextauth]/route.ts
import { handlers } from "@/auth"

export const { GET, POST } = handlers
3. ミドルウェアを追加する(任意ですが推奨)
// middleware.ts
export { auth as middleware } from "@/auth"

export const config = {
  matcher: ["/((?!api|_next/static|_next/image|favicon.ico).*)"],
}
4. 環境変数
# .env.local
AUTH_SECRET=your-secret-here  # Generate with: npx auth secret
AUTH_GITHUB_ID=your_github_client_id
AUTH_GITHUB_SECRET=your_github_client_secret

# CRITICAL: In production, AUTH_SECRET is REQUIRED
5. コンポーネントで使用する

サーバーコンポーネント(App Router):

import { auth } from "@/auth"

export default async function Dashboard() {
  const session = await auth()

  if (!session?.user) {
    return <p>Not authenticated</p>
  }

  return <p>Welcome {session.user.name}</p>
}

クライアントコンポーネント:

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

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

  if (status === "loading") return <p>Loading...</p>
  if (status === "unauthenticated") return <p>Not authenticated</p>

  return <p>Welcome {session?.user?.name}</p>
}
6. サインイン/サインアウト
import { signIn, signOut } from "@/auth"

export function SignIn() {
  return (
    <form
      action={async () => {
        "use server"
        await signIn("github")
      }}
    >
      <button type="submit">Sign in with GitHub</button>
    </form>
  )
}

export function SignOut() {
  return (
    <form
      action={async () => {
        "use server"
        await signOut()
      }}
    >
      <button type="submit">Sign Out</button>
    </form>
  )
}

クイックスタート:Cloudflare Workers

前提条件
npm create cloudflare@latest my-auth-worker
cd my-auth-worker
インストール
npm install @auth/core@latest
npm install @auth/d1-adapter@latest
npm install hono
1. D1 を使用して Wrangler を設定する
// wrangler.jsonc
{
  "name": "my-auth-worker",
  "main": "src/index.ts",
  "compatibility_date": "2025-10-26",
  "d1_databases": [
    {
      "binding": "DB",
      "database_name": "auth_db",
      "database_id": "your-database-id"
    }
  ]
}
2. D1 データベースを作成する
# Create database
npx wrangler d1 create auth_db

# Copy the database_id to wrangler.jsonc

# Create tables
npx wrangler d1 execute auth_db --file=./schema.sql

schema.sql:

-- See templates/cloudflare-workers/schema.sql for complete schema
CREATE TABLE users (
  id TEXT PRIMARY KEY,
  name TEXT,
  email TEXT UNIQUE NOT NULL,
  emailVerified INTEGER,
  image TEXT
);

CREATE TABLE accounts (
  id TEXT PRIMARY KEY,
  userId TEXT NOT NULL,
  type TEXT NOT NULL,
  provider TEXT NOT NULL,
  providerAccountId TEXT NOT NULL,
  refresh_token TEXT,
  access_token TEXT,
  expires_at INTEGER,
  token_type TEXT,
  scope TEXT,
  id_token TEXT,
  session_state TEXT,
  FOREIGN KEY (userId) REFERENCES users(id) ON DELETE CASCADE,
  UNIQUE(provider, providerAccountId)
);

CREATE TABLE sessions (
  id TEXT PRIMARY KEY,
  userId TEXT NOT NULL,
  expires INTEGER NOT NULL,
  sessionToken TEXT UNIQUE NOT NULL,
  FOREIGN KEY (userId) REFERENCES users(id) ON DELETE CASCADE
);

CREATE TABLE verification_tokens (
  identifier TEXT NOT NULL,
  token TEXT UNIQUE NOT NULL,
  expires INTEGER NOT NULL,
  PRIMARY KEY (identifier, token)
);
3. Auth を備えた Worker を作成する
// src/index.ts
import { Hono } from 'hono'
import { Auth } from '@auth/core'
import { D1Adapter } from '@auth/d1-adapter'
import GitHub from '@auth/core/providers/github'

type Bindings = {
  DB: D1Database
  AUTH_SECRET: string
  AUTH_GITHUB_ID: string
  AUTH_GITHUB_SECRET: string
}

const app = new Hono<{ Bindings: Bindings }>()

app.all('/api/auth/*', async (c) => {
  const response = await Auth(c.req.raw, {
    adapter: D1Adapter(c.env.DB),
    providers: [
      GitHub({
        clientId: c.env.AUTH_GITHUB_ID,
        clientSecret: c.env.AUTH_GITHUB_SECRET,
      }),
    ],
    secret: c.env.AUTH_SECRET,
    trustHost: true,
  })
  return response
})

app.get('/', async (c) => {
  // Example: Get session
  const session = await Auth(c.req.raw, {
    adapter: D1Adapter(c.env.DB),
    providers: [],
    secret: c.env.AUTH_SECRET,
  })

  return c.json({ session })
})

export default app
4. 環境変数
# Add secrets to Cloudflare Workers
npx wrangler secret put AUTH_SECRET
npx wrangler secret put AUTH_GITHUB_ID
npx wrangler secret put AUTH_GITHUB_SECRET
5. デプロイする
npx wrangler deploy

基本概念

セッション戦略

Auth.js v5 は、2 つのセッション戦略をサポートしています。

  1. JWT(JSON Web Token) - アダプターが設定されていない場合のデフォルト

    • ✅ エッジランタイムで動作します
    • ✅ セッションのデータベースクエリが不要です
    • ✅ 高速でスケーラブルです
    • ❌ サーバー側でセッションを無効化できません
    • ❌ トークンサイズに制限があります
  2. データベース - アダプターが設定されている場合のデフォルト

    • ✅ セッションを完全に制御できます(無効化、延長)
    • ✅ データベースに監査証跡を残せます
    • ✅ トークンサイズに制限がありません
    • ❌ リクエストごとにデータベースクエリが必要です
    • ❌ すべてのエッジランタイムと互換性があるわけではありません

選択マトリックス:

ユースケース推奨される戦略理由
Next.js App RouterJWTエッジランタイムとの互換性
Cloudflare WorkersJWT またはデータベース(D1 使用)D1 はエッジと互換性があります
従来の Node.jsデータベースセッションを完全に制御できます
高いセキュリティが必要データベースセッションを無効化できます
読み取り専用セッションJWTデータベースのオーバーヘッドがありません

詳しい比較については、references/session-strategies.md を参照してください。


セッション戦略

JWT セッション(デフォルト)

使用する状況:

  • エッジランタイムにデプロイする場合(Cloudflare Workers、Vercel Edge)
  • データベースアダプターが設定されていない場合
  • セッションデータが読み取り専用の場合
  • トラフィックの多いアプリケーションの場合(DB クエリが不要)

設定:

export const { handlers, auth } = NextAuth({
  session: {
    strategy: "jwt",
    maxAge: 30 * 24 * 60 * 60, // 30 days
  },
  providers: [GitHub],
})

⚠️ 重要: アダプターを設定している場合でも、エッジランタイムとの互換性を確保するには strategy: "jwt" を明示的に設定する必要があります!

データベースセッション

使用する状況:

  • Node.js ランタイム(エッジではない)
  • サーバー側でセッションを無効化する必要がある場合
  • コンプライアンス要件がある場合(監査証跡)
  • セッションデータが JWT の制限を超える場合

設定:

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

export const { handlers, auth } = NextAuth({
  adapter: PrismaAdapter(prisma),
  session: {
    strategy: "database",
    maxAge: 30 * 24 * 60 * 60,
    updateAge: 24 * 60 * 60, // Update session every 24 hours
  },
  providers: [GitHub],
})

⚠️ エッジランタイムの制限:

アダプターがエッジと互換性がない場合、エッジランタイム(ミドルウェア)ではデータベースセッションを使用できません。設定を分割してください。

// auth.config.ts (edge-compatible)
export default {
  providers: [GitHub],
} satisfies NextAuthConfig

// auth.ts (full config with database)
import authConfig from "./auth.config"

export const { handlers, auth } = NextAuth({
  adapter: PrismaAdapter(prisma), // Not edge-compatible
  session: { strategy: "jwt" }, // FORCE JWT for middleware
  ...authConfig,
})

プロバイダーの設定

OAuth プロバイダー(GitHub、Google など)

GitHub:

import GitHub from "next-auth/providers/github"

export const { handlers, auth } = NextAuth({
  providers: [
    GitHub({
      clientId: process.env.AUTH_GITHUB_ID,
      clientSecret: process.env.AUTH_GITHUB_SECRET,
    }),
  ],
})

Google(トークン更新あり):

import Google from "next-auth/providers/google"

export const { handlers, auth } = NextAuth({
  providers: [
    Google({
      clientId: process.env.AUTH_GOOGLE_ID,
      clientSecret: process.env.AUTH_GOOGLE_SECRET,
      authorization: {
        params: {
          prompt: "consent",
          access_type: "offline",
          response_type: "code",
        },
      },
    }),
  ],
})

完全な例については、templates/providers/oauth-github-google.ts を参照してください。

Credentials プロバイダー(メールアドレス/パスワード)

⚠️ 重要: Credentials プロバイダーがサポートするのは JWT セッションのみです!

import Credentials from "next-auth/providers/credentials"
import { z } from "zod"
import bcrypt from "bcryptjs"

const signInSchema = z.object({
  email: z.string().email(),
  password: z.string().min(8),
})

export const { handlers, auth } = NextAuth({
  providers: [
    Credentials({
      credentials: {
        email: { label: "Email", type: "email" },
        password: { label: "Password", type: "password" },
      },
      authorize: async (credentials) => {
        try {
          const { email, password } = await signInSchema.parseAsync(credentials)

          // Fetch user from database
          const user = await db.user.findUnique({ where: { email } })

          if (!user || !user.password) {
            // CRITICAL: Return null, DON'T throw
            return null
          }

          const passwordMatch = await bcrypt.compare(password, user.password)

          if (!passwordMatch) {
            return null
          }

          // Return user object
          return {
            id: user.id,
            email: user.email,
            name: user.name,
          }
        } catch (error) {
          // CRITICAL: Return null on error, DON'T throw
          console.error("Auth error:", error)
          return null
        }
      },
    }),
  ],
})

⚠️ 重要なルール:

  1. authorize() では決してエラーをスローしないでください。常に null を返してください
  2. 理由: エラーをスローすると、CredentialsSignin ではなく CallbackRouteError が発生します
  3. 認証情報を確認する前に、必ず Zod で検証してください
  4. パスワードは bcrypt でハッシュ化し、平文で保存しないでください

完全な例については、templates/providers/credentials.ts を参照してください。

Magic Link プロバイダー(パスワードレス)

⚠️ 重要: Magic Link にはデータベースアダプターが必須です!

import Resend from "next-auth/providers/resend"
import { PrismaAdapter } from "@auth/prisma-adapter"

export const { handlers, auth } = NextAuth({
  adapter: PrismaAdapter(prisma), // REQUIRED
  providers: [
    Resend({
      apiKey: process.env.AUTH_RESEND_KEY,
      from: "[email protected]",
    }),
  ],
})

完全な例については、templates/providers/magic-link-resend.ts を参照してください。


データベースアダプター

Cloudflare D1 アダプター

インストール:

npm install @auth/d1-adapter@latest

Wrangler の設定:

// wrangler.jsonc
{
  "d1_databases": [
    {
      "binding": "DB",
      "database_name": "auth_db",
      "database_id": "your-database-id"
    }
  ]
}

使用方法:

import { D1Adapter } from "@auth/d1-adapter"

// Cloudflare Workers
const app = new Hono<{ Bindings: { DB: D1Database } }>()

app.all('/api/auth/*', async (c) => {
  return await Auth(c.req.raw, {
    adapter: D1Adapter(c.env.DB),
    providers: [GitHub],
  })
})

// Next.js (with D1 via wrangler)
export const { handlers, auth } = NextAuth({
  adapter: D1Adapter(env.DB),
  session: { strategy: "jwt" }, // Recommended for edge
  providers: [GitHub],
})

データベーススキーマ:

完全なスキーマについては、templates/cloudflare-workers/schema.sql を参照してください。

エッジとの互換性: ✅ D1 は完全にエッジと互換性があります!

Prisma アダプター(PostgreSQL/MySQL)

インストール:

npm install @auth/prisma-adapter@latest
npm install @prisma/client@latest
npm install -D prisma@latest

Prisma スキーマ:

// prisma/schema.prisma
generator client {
  provider = "prisma-client-js"
}

datasource db {
  provider = "postgresql"
  url      = env("DATABASE_URL")
}

model User {
  id            String    @id @default(cuid())
  name          String?
  email         String    @unique
  emailVerified DateTime?
  image         String?
  accounts      Account[]
  sessions      Session[]
}

model Account {
  id                String  @id @default(cuid())
  userId            String
  type              String
  provider          String
  providerAccountId String
  refresh_token     String? @db.Text
  access_token      String? @db.Text
  expires_at        Int?
  token_type        String?
  scope             String?
  id_token          String? @db.Text
  session_state     String?

  user User @relation(fields: [userId], references: [id], onDelete: Cascade)

  @@unique([provider, providerAccountId])
}

model Session {
  id           String   @id @default(cuid())
  sessionToken String   @unique
  userId       String
  expires      DateTime
  user         User     @relation(fields: [userId], references: [id], onDelete: Cascade)
}

model VerificationToken {
  identifier String
  token      String   @unique
  expires    DateTime

  @@unique([identifier, token])
}

使用方法:

import { PrismaAdapter } from "@auth/prisma-adapter"
import { PrismaClient } from "@prisma/client"

const prisma = new PrismaClient()

export const { handlers, auth } = NextAuth({
  adapter: PrismaAdapter(prisma),
  session: { strategy: "jwt" }, // For edge compatibility
  providers: [GitHub],
})

エッジとの互換性: ❌ Prisma はデフォルトではエッジと互換性がありません

回避策: エッジとの互換性を確保するには Prisma Accelerate または Hyperdrive を使用するか、JWT セッションを強制し、ミドルウェアではアダプターを使用しないでください。

完全な例については、templates/database-adapters/prisma-postgresql.ts を参照してください。


ミドルウェアのパターン

セッションの有効期限を延長
// middleware.ts
export { auth as middleware } from "@/auth"

export const config = {
  matcher: ["/((?!api|_next/static|_next/image|favicon.ico).*)"],
}

これにより、すべてのリクエストでセッションの有効期限が自動的に更新されます。

ルートの保護
// middleware.ts
import { auth } from "@/auth"
import { NextResponse } from "next/server"

export default auth((req) => {
  const { pathname } = req.nextUrl

  // Protect /dashboard routes
  if (pathname.startsWith("/dashboard")) {
    if (!req.auth) {
      const loginUrl = new URL("/login", req.url)
      loginUrl.searchParams.set("callbackUrl", pathname)
      return NextResponse.redirect(loginUrl)
    }
  }

  return NextResponse.next()
})

export const config = {
  matcher: ["/((?!api|_next/static|_next/image|favicon.ico).*)"],
}
ロールベースのアクセス制御(RBAC)
// auth.ts
export const { handlers, auth } = NextAuth({
  providers: [GitHub],
  callbacks: {
    async jwt({ token, user }) {
      // Add role to JWT on sign in
      if (user) {
        token.role = user.role
      }
      return token
    },
    async session({ session, token }) {
      // Expose role to session
      if (session.user) {
        session.user.role = token.role
      }
      return session
    },
  },
})
// middleware.ts
import { auth } from "@/auth"
import { NextResponse } from "next/server"

export default auth((req) => {
  const { pathname } = req.nextUrl

  // Protect /admin routes (require admin role)
  if (pathname.startsWith("/admin")) {
    if (!req.auth || req.auth.user.role !== "admin") {
      return NextResponse.redirect(new URL("/unauthorized", req.url))
    }
  }

  return NextResponse.next()
})

完全な例については、references/middleware-patterns.md および templates/advanced/role-based-access.ts を参照してください。


高度な機能

JWT コールバック(カスタムクレーム)
export const { handlers, auth } = NextAuth({
  providers: [GitHub],
  callbacks: {
    async jwt({ token, user, account }) {
      // On sign in
      if (user) {
        token.id = user.id
        token.role = user.role
      }

      // On subsequent requests
      return token
    },
    async session({ session, token }) {
      // Expose custom claims to session
      session.user.id = token.id
      session.user.role = token.role
      return session
    },
  },
})
トークンの更新(OAuth)

トークン更新を伴う Google OAuth:

import Google from "next-auth/providers/google"

export const { handlers, auth } = NextAuth({
  providers: [
    Google({
      authorization: {
        params: {
          prompt: "consent",
          access_type: "offline",
          response_type: "code",
        },
      },
    }),
  ],
  callbacks: {
    async jwt({ token, account }) {
      // First-time login, save tokens
      if (account) {
        return {
          ...token,
          access_token: account.access_token,
          expires_at: account.expires_at,
          refresh_token: account.refresh_token,
        }
      }

      // Subsequent logins, check if token expired
      if (Date.now() < token.expires_at * 1000) {
        return token
      }

      // Token expired, refresh it
      try {
        const response = await fetch("https://oauth2.googleapis.com/token", {
          method: "POST",
          body: new URLSearchParams({
            client_id: process.env.AUTH_GOOGLE_ID!,
            client_secret: process.env.AUTH_GOOGLE_SECRET!,
            grant_type: "refresh_token",
            refresh_token: token.refresh_token!,
          }),
        })

        const newTokens = await response.json()

        return {
          ...token,
          access_token: newTokens.access_token,
          expires_at: Math.floor(Date.now() / 1000 + newTokens.expires_in),
          refresh_token: newTokens.refresh_token ?? token.refresh_token,
        }
      } catch (error) {
        console.error("Token refresh error:", error)
        token.error = "RefreshTokenError"
        return token
      }
    },
    async session({ session, token }) {
      session.error = token.error
      return session
    },
  },
})

完全な例については、templates/advanced/jwt-refresh-tokens.ts を参照してください。


重要なルール

✅ 必ず行うこと:
  1. 本番環境では AUTH_SECRET を設定する

    # Generate secret
    npx auth secret
    
    # Add to .env.local
    AUTH_SECRET=your-generated-secret
    
  2. Credentials の authorize() では例外をスローせず、null を返す

    authorize: async (credentials) => {
      if (!validUser) {
        return null // ✅ Correct
        // throw new Error("Invalid") // ❌ WRONG - causes CallbackRouteError
      }
    }
    
  3. マジックリンクにはアダプターを使用する

    export const { handlers, auth } = NextAuth({
      adapter: PrismaAdapter(prisma), // REQUIRED for magic links
      providers: [Resend],
    })
    
  4. エッジとの互換性を確保するため、設定を分割する

    // auth.config.ts (edge-compatible)
    export default { providers: [GitHub] }
    
    // auth.ts (full config with database)
    export const { handlers, auth } = NextAuth({
      adapter: PrismaAdapter(prisma),
      session: { strategy: "jwt" }, // Force JWT for edge
      ...authConfig,
    })
    
  5. エッジ非対応のアダプターを使用する場合は、JWT セッションを強制する

    export const { handlers, auth } = NextAuth({
      adapter: PrismaAdapter(prisma), // Not edge-compatible
      session: { strategy: "jwt" }, // CRITICAL
    })
    
❌ 絶対に行わないこと:
  1. AUTH_SECRET を設定せずにデプロイする

    // WRONG - will fail in production
    // Missing AUTH_SECRET environment variable
    
  2. authorize() でエラーをスローする

    authorize: async (credentials) => {
      throw new Error("Invalid credentials") // ❌ Causes CallbackRouteError
    }
    
  3. 非推奨の @next-auth/ アダプターを使用する*

    npm install @next-auth/prisma-adapter  # ❌ Deprecated
    npm install @auth/prisma-adapter       # ✅ Correct (v5)
    
  4. ミドルウェアで、エッジ対応アダプターを使わずにデータベースセッションを使用する

    // WRONG - Prisma not edge-compatible
    export const { handlers, auth } = NextAuth({
      adapter: PrismaAdapter(prisma),
      session: { strategy: "database" }, // ❌ Fails in middleware
    })
    
  5. v4 と v5 のパッケージを混在させる

    npm install [email protected] @auth/[email protected]  # ❌ Version mismatch
    

よくあるエラーと解決方法

1. AUTH_SECRET が設定されていない

エラー:

JWEDecryptionFailed: Invalid secret

原因: AUTH_SECRET 環境変数が設定されていないか、値が正しくありません

解決方法:

# Generate secret
npx auth secret

# Add to .env.local
AUTH_SECRET=your-generated-secret

# In production (Vercel, Cloudflare, etc.)
# Add AUTH_SECRET as environment variable in dashboard
2. CallbackRouteError

エラー:

CallbackRouteError: Illegal arguments: string, undefined

原因: authorize() コールバックでエラーをスローしています

解決方法:

// WRONG
authorize: async (credentials) => {
  if (!user) throw new Error("Invalid credentials")
}

// CORRECT
authorize: async (credentials) => {
  if (!user) return null
  return user
}
3. ルートが見つからない

エラー:

Error: next-auth route not found

原因: API ルートハンドラーのファイルパスが正しくありません

解決方法:

// Ensure file is at EXACT path:
// app/api/auth/[...nextauth]/route.ts

import { handlers } from "@/auth"
export const { GET, POST } = handlers
4. エッジ互換性エラー

エラー:

Module not compatible with edge runtime

原因: データベースセッション戦略でエッジ非対応のアダプターを使用しています

解決方法:

// Option 1: Force JWT sessions
export const { handlers, auth } = NextAuth({
  adapter: PrismaAdapter(prisma),
  session: { strategy: "jwt" }, // ✅
})

// Option 2: Use edge-compatible adapter (D1)
export const { handlers, auth } = NextAuth({
  adapter: D1Adapter(env.DB), // ✅ Edge-compatible
  session: { strategy: "database" },
})
5. セッションが更新されない

エラー: セッションの有効期限が切れても更新されません

原因: ミドルウェアがありません

解決方法:

// middleware.ts
export { auth as middleware } from "@/auth"

export const config = {
  matcher: ["/((?!api|_next/static|_next/image|favicon.ico).*)"],
}
6~12. その他のエラー

修正方法を含む、文書化された全 12 件のエラーについては、references/common-errors.md を参照してください。


テンプレートのリファレンス

すべてのテンプレートは templates/ ディレクトリにあります。

Next.js テンプレート(5 件)
  • auth.ts - シンプルな Next.js 設定(JWT セッション)
  • auth.config.ts + auth.ts - 分割設定(エッジ対応)
  • multi-provider.ts - OAuth + Credentials + マジックリンク
  • middleware.ts - セッションの維持 + ルート保護
  • package.json + .env.example - 依存関係 + 環境設定
Cloudflare Workers テンプレート(3 件)
  • worker-hono-auth.ts - Hono + Auth.js + D1 の完全な構成
  • wrangler.jsonc - D1 バインディング設定
  • schema.sql - Auth.js 用 D1 テーブル
プロバイダーテンプレート(3 件)
  • oauth-github-google.ts - OAuth の設定
  • credentials.ts - Zod による検証を使用したメールアドレス/パスワード認証
  • magic-link-resend.ts - パスワードレスのメール認証
高度なテンプレート(2 件)
  • jwt-refresh-tokens.ts - Google トークンのローテーション例
  • role-based-access.ts - カスタムクレームによる RBAC

これらのファイルをプロジェクトにコピーし、必要に応じてカスタマイズしてください。


パッケージのバージョン

現在(2025-10-26 時点):

{
  "next-auth": "4.24.11",
  "@auth/core": "0.41.1",
  "@auth/d1-adapter": "1.11.1",
  "@auth/prisma-adapter": "2.7.5",
  "next": "15.3.1",
  "hono": "4.7.9"
}

常に最新バージョンを使用してください:

npm install next-auth@latest @auth/core@latest

公式ドキュメント


リファレンスドキュメント

詳しくは、以下を参照してください。

  • common-errors.md - 文書化されたすべてのエラー 12 件とその解決方法
  • edge-compatibility.md - エッジランタイムの互換性マトリックス
  • v5-migration-guide.md - v4 → v5 の破壊的変更
  • session-strategies.md - JWT とデータベースの比較
  • middleware-patterns.md - ルート保護、RBAC
  • jwt-customization.md - カスタムクレーム、トークンの更新
  • provider-setup-guides.md - OAuth アプリの設定手順

質問や問題がありますか?

  1. まず references/common-errors.md を確認してください
  2. AUTH_SECRET が設定されていることを確認してください
  3. authorize() でエラーをスローしていないことを確認してください
  4. 使用しているアダプターのエッジ互換性を確認してください
  5. 公式ドキュメントを確認してください:https://authjs.dev

コメント