Auth.js+NEXT.sのCredentialでログイン失敗した時のエラー画面をカスタム

Auth.js+NEXT.sのCredential(パスワード、メールアドレス)でログイン時にエラーになった時の
エラー画面のカスタム方法を備忘録として残します。

公式のドキュメントでも一応やり方は紹介されてます。
https://authjs.dev/guides/pages/error?framework=next-js

しかし、自分の環境ではうまくいかないところもあったので
どうすればうまくいったかを説明します。

まず、auth.tsにエラーページのルートを定義します。
ルートは自由に設定できます。

```typescript:auth.ts
import NextAuth from "next-auth"
import Credentials from "next-auth/providers/credentials"//emailとパスワードでログインするために使用


export const { handlers, signIn, signOut, auth } = NextAuth({
    providers: [
        Credentials({
            credentials: {
                email: {},
                password: {},
            },
            authorize: async (credentials) => {
      
                // ログイン処理

            },
          }),
    ],
    callbacks: {
        //省略
    },

    //ルートを定義
    pages: {
        error: "/auth/error",
    }
      
})
```
今回は、"/auth/error"というルートにしました。
app routerでページの表示を行っているので、"/auth/error"にアクセスした際に
カスタムしたページが表示されるようにします。src>appの中にauthディレクトリを作り、
その中にerrorディレクトリを作り、その中にpage.tsxを作成します

このpage.tsxがカスタムエラーページになります。
公式ドキュメントの例を参考に、下記のように作ってみました。

```typescript:/src/app/auth/error/page.tsx
"use client"
 
import { useSearchParams } from "next/navigation"
 
enum Error {
  Configuration = "Configuration",
}
 
const errorMap = {
  [Error.Configuration]: (
    <p>
        ログイン時に問題が起きました。
    </p>
  ),
}
 
export default function AuthErrorPage() {
  const search = useSearchParams()
  const error = search.get("error") as Error
 
  return (
    <div className="flex h-screen w-full flex-col items-center justify-center">
      <div
        className="block max-w-lg rounded-lg border border-gray-200 bg-white p-6 text-center shadow hover:bg-gray-100 dark:border-gray-700 dark:bg-gray-800 dark:hover:bg-gray-700"
      >
        <h5 className="mb-2 flex flex-row items-center justify-center gap-2 text-xl font-bold tracking-tight text-rose-600">
          ログインできませんでした
        </h5>
        <div className="font-normal text-gray-700 dark:text-gray-400">
          {errorMap[error] || "Please contact us if this error persists."}
        </div>
      </div>
    </div>
  )
}
```

【追記】
カスタムページでuseSearchParamsを使用していますが、
その場合、Suspenseでワラップしないと本番環境でbuild時にエラーになります。

https://nextjs.org/docs/messages/missing-suspense-with-csr-bailout

対策として、layout.tsxに(layoy.tsxを消してる場合はエラーのpage.tsxに)
Suspenseでワラップするように追記します。

```layout.tsx
import type { Metadata } from "next";
import { Geist, Geist_Mono } from "next/font/google";
import "./globals.css";
import AuthProvider from "@/providers/AuthProvider";
import { Suspense } from 'react'

const geistSans = Geist({
  variable: "--font-geist-sans",
  subsets: ["latin"],
});

const geistMono = Geist_Mono({
  variable: "--font-geist-mono",
  subsets: ["latin"],
});

export const metadata: Metadata = {
  title: "Create Next App",
  description: "Generated by create next app",
};

export default function RootLayout({
  children,
}: Readonly<{
  children: React.ReactNode;
}>) {
  return (
    <html lang="en">
        <body
            className={`${geistSans.variable} ${geistMono.variable} bg-gray-200 antialiased`}
        >
        <Suspense> //ワラップ
          <AuthProvider>
              {children}
          </AuthProvider>          
        </Suspense>
        </body>
    </html>
  );
}

```


以上がエラーページのカスタム方法です。