Open3

NextAuthについて

ふくしまふくしま

400ばかり帰ってくる

/api/authのエンドポイントに繋いだところ、以下エラーが出る。
Error: This action with HTTP GET is not supported by NextAuth.js

なんてことはない。こちらのファイルの置きミスだった。
src/app/[...nextauth]/route.ts にきちんと置くこと。
NextAuthの公式ドキュメントを参照せず、誰かが書いたページを鵜呑みにしてしまっていた。
公式ドキュメント(App Router): https://next-auth.js.org/configuration/initialization#route-handlers-app

(しかしNextAuthのApp Routerのドキュメント見つけにくいよ。。。)

ふくしまふくしま

DBにemailやnameを保存したくない

NextAuthのPrisma AdapterでOIDCするとemailやnameをDBに保存する設定にデフォルトではなっている。
それを回避したい。

/usr/src/app/src/app/api/auth/[...nextauth]/route.ts

以下のようにscopeとprofileの設定をオーバーライドすることでemailやnameを使わないようにした
参考: https://github.com/nextauthjs/next-auth/blob/v4/packages/next-auth/src/providers/google.ts

import NextAuth from "next-auth/next";
import GoogleProvider from "next-auth/providers/google";
import { PrismaAdapter } from "@auth/prisma-adapter";
import { PrismaClient } from "@prisma/client";

const prisma = new PrismaClient();

const handler = NextAuth({
  session: {
    strategy: "database",
  },
  adapter: PrismaAdapter(prisma),
  providers: [
    GoogleProvider({
      clientId: process.env.GOOGLE_CLIENT_ID || "",
      clientSecret: process.env.GOOGLE_CLIENT_SECRET || "",
      authorization: { params: { scope: "openid" } },
      profile(profile) {
        return {
          id: profile.sub,
        };
      },
    }),
  ],
  secret: process.env.NEXTAUTH_SECRET,
});

export { handler as GET, handler as POST };

/usr/src/app/prisma/schema.prisma

スキーマのUserモデルからもname, email, imageを消した。emailVerifiedは残さないとエラーが起きるので残している(何かはわかっていない)。
参考: https://authjs.dev/getting-started/adapters/prisma

model User {
  id            String          @id @default(cuid())
  emailVerified DateTime?
  accounts      Account[]
  sessions      Session[]
 
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt
}
ふくしまふくしま

sessionに任意のフィールドを追加したい

表題の通り、sessionにuserIdとかを追加したい。
「いやいやcallbackに追加するだけでしょ?」と思っていたのですが、buildしたときにsessionオブジェクトにフィールドがないとかでエラーが起きます。これは困る。

困ったなと思っていたら、以下の記事に書いてあった。
参考: https://annjose.com/post/how-to-customize-nextauth-session/

src/types/next-auth.d.ts に拡張したsessionオブジェクトを書くだけ。以下の感じ。

import NextAuth from "next-auth";

declare module "next-auth" {
  interface Session {
    userId: string;
  }
}

あと自分で設定した認証方法(databaseによるsessionとか)で getServerSession() を使いたい場合、nextAuthOptionsをexportする必要がある。ここで
src/app/api/auth/[...nextauth]/route.ts に nextAuthOptions を直接書いて export してはいけない。これは、[...nextauth]/route.ts ではexportするオブジェクトが決まっているため。

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

import NextAuth from "next-auth/next";
import { nextAuthOptions } from "./authOptions";

const handler = NextAuth(nextAuthOptions);
export { handler as GET, handler as POST };

src/app/api/auth/[...nextauth]/authOptions.ts

import GoogleProvider from "next-auth/providers/google";
import { PrismaAdapter } from "@auth/prisma-adapter";
import { PrismaClient } from "@prisma/client";
import type { NextAuthOptions } from "next-auth";

const prisma = new PrismaClient();

export const nextAuthOptions: NextAuthOptions = {
  session: {
    strategy: "database",
  },
  adapter: PrismaAdapter(prisma),
  providers: [
    GoogleProvider({
      clientId: process.env.GOOGLE_CLIENT_ID || "",
      clientSecret: process.env.GOOGLE_CLIENT_SECRET || "",
      authorization: { params: { scope: "openid" } },
      profile(profile) {
        return {
          id: profile.sub,
        };
      },
    }),
  ],
  secret: process.env.NEXTAUTH_SECRET,
  callbacks: {
    async session({ session, user }) {
      if (session?.user) {
        session.userId = user.id;
      }
      return session;
    },
  },
};