Open6

next-auth@5.0.0(Auth.js) メモ

atnuhsatnuhs

strategy

  • ユーザセッションの保存方法
  • デフォルトではjwtになり、Cookieに保存される
  • アダプタ(データベース)を使用する場合は、databaseになる
    • ただし、明示的にjwtと定義することで、jwtセッションを強制できる
auth.ts
// データベースを使用し、jwtも使用する場合
export const { handlers, signIn, signOut, auth } = NextAuth({
  ...authConfig,
  adapter: PrismaAdapter(prisma),
  session: {strategy: "jwt"},
  callbacks: {
    session: ({token, session, user}) => {
      return {
        ...session,
        user: {
          ...session.user,
          id: token.sub
        }
      }
    }
  }
});

OAuthを使用する場合デフォルトで取れる認証情報は以下のものである。

  • name
  • email
  • image

これだけだと不十分なので、今回はSession callbackの中でuser.idにユーザーIDであるtoken.subを追加している。

atnuhsatnuhs

jwt callback

ここでreturnされるものはすべてJWTに保存され、session callbackに転送される。
引数のuseraccountprofileはサインイン時のみ渡される。

auth.ts
 callbacks: {
    async jwt({ token, user, account, trigger, session }) {
      // サインイン時
      if (user) {
        token.name = user.name;
      }

      // セッション更新時の処理
      if (trigger == "update" && session?.name) {
        console.log("-- セッション更新 --")
        token.name = session.name;
        token.isNewUser = false; // 名前が設定されたらNewUserをfalseに
      }
      return token;
    },

Prismaを使用する場合、引数のuserの中身はschema.prismaによって決まる
accountはほぼスキーマ通りだったが違う部分も見られた。

user
 "user": {
    "id": "xxxxxxxxxxxxxxxxxxxxxxx",
    "name": "atnuhs",
    "email": "xxxxxxxxxx@gmail.com",
    "emailVerified": null,
    "image": "https://xxxxxxxxxxxxxxxxxxxxxxxxx"
  },
token
token:  {
  name: 'atnuhs',
  email: 'xxxxxxxxxx@gmail.com',
  picture: 'https://xxxxxxxxxxxxx',
  sub: 'xxxxxxxxxxxxx' // user.idと一緒
}
account
account:  {
  access_token: 'xxxxxxxxxxxxx',
  expires_in: 3599,
  scope: 'https://www.googleapis.com/auth/userinfo.profile openid https://www.googleapis.com/auth/userinfo.email',
  token_type: 'bearer',
  id_token: 'xxxxxxxxxxxxx',
  expires_at: 1728144477,
  provider: 'google',
  type: 'oidc',
  providerAccountId: 'xxxxxxxxxxxxxxxxxxxx'
}
profile
  "profile": {
    "iss": "https://accounts.google.com",
    "azp": "xxxxxxxxxxx",
    "aud": "xxxxxxxxxxxxxx",
    "sub": "xxxxxxxxxxxx",
    "email": "xxxxxxxx@gmail.com",
    "email_verified": true,
    "at_hash": "xxxxxxx",
    "name": "atnuhs",
    "picture": "https://xxxxxxxx",
    "given_name": "atnuhs",
    "iat": 1728123231,
    "exp": 1728126831
  },

session callback

sessionがチェックされるたびに呼び出される。

  • const session = auth()を呼び出したときにsessionに入る値を決める。
  • token引数はjwt session strategyを使用しているとき、user引数はdatabase session strategyを使用しているときのみ使用可能。(例:jwt strategyを使用しているときはuser引数はundefinedになる)
  • token引数はjwt callbackでtokenに追加したものが入る。
  • user引数はDBに保存されたUserデータが入る。

以下はsessionにuserIdを追加する例:

auth.ts
callbacks: {
    session: ({ token, session, user }) => {
      return {
        ...session,
        user: {
          ...session.user,
          id: token.sub,
        },
      };
    },
  },
atnuhsatnuhs

型定義の拡張について

  • "next-auth"のUserがjwt callbackのuserの定義
  • "next-auth/jwt"のJWTがjwt callbackとsession callbackのtokenの定義
  • ※AdapterUserの拡張は必要だった気がしたけど、なくてもいけたので要調査
  • わかんなくなったときはauth.tsで引数をホバーしたらわかると思う
next-auth.d.ts
import { UserRole } from "@prisma/client";
import NextAuth, {type DefaultSession } from "next-auth"

declare module "next-auth" {
  interface Session {
    user: {
      id: string;
      isProfileComplete: boolean; // 追加
      role: UserRole; // 追加
      
    } & DefaultSession['user'];
  }

  // jwt callbackのuser
  interface User {
    id: string;
    name: string;
    email: string;
    emailVerified: boolean;
    image: string;
    isProfileComplete: boolean;  // 追加
    role: UserRole;  // 追加
  }
}

declare module "next-auth/jwt" {
  // jwt callbackとsession callbackのtoken
  interface JWT {
    role: UserRole; // 追加
    isProfileComplete: boolean; // 追加
  }
}

declare module "@auth/core/adapters" {
  interface AdapterUser extends User {
    isProfileComplete: boolean; // 追加
    role: UserRole; // 追加
  }
}