🙄

Next.jsをNextAuth.js v4からAuth.js(NextAuth.js v5)に移行する

2024/12/07に公開

はじめに

Auth.jsは、Next.js用に開発されていたNextAuth.jsから進化し、標準的なWeb APIをベースとした認証ライブラリです。

Next.jsなどのフレームワークでログインやセッション管理をするには定番のライブラリと言っていいでしょう。

NextAuth.js v4からNextAuth.js(Auth.js) v5に移行するにあたって、いくつか破壊的変更が入ったので設定ファイルや各種メソッドの呼び出し等を変更し、移行する必要があります。

執筆現在(2024/12/07)ではAuth.js v5はbeta版ですが、移行準備をしたり、さっさと乗り換えたいという人向けの記事です。

現在のAuth.js公式ドキュメントのアップグレードガイドを読んだだけでは分からないところも書いていきます。

前提とする環境

  • Next.js v14以上
    • Auth.jsがNext.js v14以上を要求するため
  • NextAuth.js v4を設定した環境

手順

1. npmパッケージを最新に更新する

まず、NextAuth.js v4からAuth.js v5にアップグレードします。
※ 執筆現在は、まだbetaであることに留意してください

npm install next-auth@beta

2. 空の設定ファイルの作成

auth.tsauth.config.tsファイルを作成します。

多くの場合は、プロジェクルートの直下か、srcディレクトリでソースを管理している場合はsrc直下にファイルを作成することになるでしょう。

3. 設定ファイルの内容を移す

NextAuth.js v4のファイル内容をv5に移行しましょう。
ここでは実際に移行したファイルを例にします。

src/app/next-auth-options.ts
import { FirestoreAdapter } from "@auth/firebase-adapter";
import { cert } from "firebase-admin/app";
import { type Adapter } from "next-auth/adapters";
import GoogleProvider from "next-auth/providers/google";
import { type GoogleProfile } from "next-auth/providers/google";

import type { JWT, NextAuthOptions, Session } from "next-auth";

export const nextAuthOptions: NextAuthOptions = {
  debug: process.env.NODE_ENV === "production" ? false : true,
  providers: [
    GoogleProvider({
      clientId: process.env.GOOGLE_CLIENT_ID!,
      clientSecret: process.env.GOOGLE_CLIENT_SECRET!,
      authorization: {
...
      },
      profile(profile: GoogleProfile) {
...
      },
    }),
  ],
  secret: process.env.NEXTAUTH_SECRET,
  session: {
    strategy: "jwt",
  },
  adapter: FirestoreAdapter({
...
  }) as Adapter,
  callbacks: {
    async jwt({ token, user, account, trigger, session }) {
...
    },
    async session({ session, token }: { session: Session; token: JWT }) {
...
    },
  },
};

設定ファイルを移行して以下のようになりました。

src/auth.ts
import NextAuth from "next-auth";

import { FirestoreAdapter } from "@auth/firebase-adapter";
import { cert } from "firebase-admin/app";
import { type Adapter } from "next-auth/adapters";

import authConfig from "./auth.config";

export const { auth, handlers, signIn, signOut } = NextAuth({
  session: {
    strategy: "jwt",
  },
  adapter: FirestoreAdapter({
...
  }) as Adapter,
  ...authConfig,
});
src/auth.config.ts
import type { NextAuthConfig } from "next-auth";
import { type GoogleProfile } from "next-auth/providers/google";
import Google from "next-auth/providers/google";

export default {
  debug: process.env.NODE_ENV === "production" ? false : true,
  providers: [
    Google({
      authorization: {
...
      },
      profile(profile: GoogleProfile) {
...
      },
    }),
  ],
  secret: process.env.NEXTAUTH_SECRET,
  callbacks: {
    async jwt({ token, user, account, trigger, session }) {
...
    },
    async session({ session, token }) {
...
    },
  },
} satisfies NextAuthConfig;

設定ファイル移行のポイント

  • 設定ファイルでエクスポートする内容が変わっています。
- import type { NextAuthOptions } from "next-auth";
+ import NextAuth from "next-auth";
- export const nextAuthOptions: NextAuthOptions = {
+ export const { auth, handlers, signIn, signOut } = NextAuth({
...
- };
+ });
  • secretオプションの指定が必要なくなりました。環境変数はデフォルトでAUTH_SECRETを読み込むようになっています。
-  secret: process.env.NEXTAUTH_SECRET,
  • 各種のprovidersのimport文のパスが変わりました
- import GoogleProvider from "next-auth/providers/google";
+ import Google from "next-auth/providers/google";
  • それに伴って下記のようにprovidersで省略できるオプションが増えています。
    • 例えばGOOGLE_CLIENT_IDAUTH_GOOGLE_IDに、GOOGLE_CLIENT_SECRETAUTH_GOOGLE_SECRETに名称を変更すれば自動で読み込まれます。
-    GoogleProvider({
+    Google({
-      clientId: process.env.GOOGLE_CLIENT_ID!,
-      clientSecret: process.env.GOOGLE_CLIENT_SECRET!,
      authorization: {
...
      },
      profile(profile: GoogleProfile) {
...
      },
    }),
  • 設定ファイルの型の書き方が変わりました
ts
- export const nextAuthOptions: NextAuthOptions = {
+ export default {
...
- };
+ } satisfies NextAuthConfig;
  • adaptersession以外はauth.config.tsファイルに定義を移動しています
auth.js
export const { auth, handlers, signIn, signOut } = NextAuth({
  session: {
    strategy: "jwt",
  },
  adapter: FirestoreAdapter({
...
  }) as Adapter,
  ...authConfig,
});

4. APIルートを書き換える

設定ファイルは2行で済むようになりました。

(1) NextAuth.js v4

app/api/auth/[...nextauth]/route.ts
import NextAuth from "next-auth";

import { nextAuthOptions } from "@/app/next-auth-options";

const handler = NextAuth(nextAuthOptions);

export { handler as GET, handler as POST };

(2) NextAuth.js v5

app/api/auth/[...nextauth]/route.ts
import { handlers } from "@/auth";
export const { GET, POST } = handlers;

5. 環境変数を変更する

  • 殆どの環境ではNEXTAUTH_URLAUTH_URLの記述は必要なくなりました
    • リクエストヘッダーに基づき自動で上記が設定されるようになっています
  • NEXTAUTH_SECRETAUTH_SECRETになりました
  • 前述のようにGOOGLE_CLIENT_IDAUTH_GOOGLE_IDに、GOOGLE_CLIENT_SECRETAUTH_GOOGLE_SECRETに名称を変更します。
    • 命名ルールは下記のとおりです
AUTH_[PROVIDER]_ID=
AUTH_[PROVIDER]_SECRET=

参考: Auth.js | Environment Variables

6. middlewareを書き換える

middlewareは下記のようにラップして書くようになりました。

middleware.ts
import authConfig from "./auth.config"
import NextAuth from "next-auth"
 
const { auth } = NextAuth(authConfig)
export default auth(async function middleware(req: NextRequest) {
  // ミドルウェアの処理をここに書く
})

7. セッションの取得処理を書き換える

サーバーコンポーネントでのセッションの取得方法がgetServerSession()ではなくauth()で取得できるようになりました。
シンプルですね。

getServerSession()を使っている箇所を片っ端からauth()に変更しましょう。

クライアントコンポーネントでは従来通りuseSession()を用いて取得します。

app/page.tsx
- import { authOptions } from "pages/api/auth/[...nextauth]"
- import { getServerSession } from "next-auth/next"
+ import { auth } from "@/auth"
 
export default async function Page() {
-  const session = await getServerSession(authOptions)
+  const session = await auth()
  return (<p>Welcome {session?.user.name}!</p>)
}

最後に

以上がNextAuth.js v4からNextAuth.js(Auth.js) v5に移行するにあたって自分が対応した内容になります。
動かなくなった時はAuth.js公式ドキュメントのアップグレードガイドなどの公式ドキュメントやAuth.jsのソースなどを参考にすることをお勧めします。

読んで頂き、ありがとうございました!!

Discussion