宮水の日記

宮水の日記

主に書評や資格取得について記事を書いています。

NextAuthのsessionに任意のプロパティを追加する

簡単な個人開発のログインで、NextAuthを使用しました。

やりたいこと

sessionオブジェクトが用意されているのですが、デフォルトだと以下の値が参照できるようになっています。

session.user.name
session.user.email
session.user.image
session.expires

私のプロダクトでは、user.idを参照できるようにしたいです。

session.user.id

sessionオブジェクトにuser.idを追加する

[...nextauth].ts ファイルのoptions: callbacksに以下のように書き、要素を追加します。

// [...nextauth].ts

import NextAuth from 'next-auth'
  - 中略 - 

const options = {
  - 中略 - 
  callbacks: {
    async session(session, user) {
      session.user.id = user.sub
      return Promise.resolve(session)
    },
  }
}

型をつける

今のままだと参照した際に型エラーになってしまうので、型をつけます。
f:id:kattyan53:20210807183656p:plain

types/next-auth.d.ts を作成し、以下のように書きます。

declare module "next-auth" {
  interface Session {
    user: {
      id: string | null
    }
  }
}

エラーがなくなりました。
f:id:kattyan53:20210807184047p:plain

何をしたのか

ライブラリの中身を見てみると、デフォルトだとDefaultSession型が参照されます。

export interface DefaultSession extends Record<string, unknown> {
  user?: {
    name?: string | null
    email?: string | null
    image?: string | null
  }
  expires?: string
}

export interface Session extends Record<string, unknown>, DefaultSession {}

今回は、独自に定義したSession型を参照するようにしました。

declare module "next-auth" {
  interface Session {
    user: {
      id: string | null
    }
  }
}

ハマったこと

デフォルトでは、Session型はDefaultSessionをextendsしています。

f:id:kattyan53:20210808040126p:plain


てっきり↓こんな感じで拡張されていると思っていたのですが、上記の型定義だとuser.idしか参照できません。

  export interface DefaultSession {
    user?: {
      name?: string | null
      email?: string | null
      image?: string | null
    }
    expires?: string
  }
  
  interface Session {
    user?: {
      id?: string | null
    }
  } 
   
  interface NewSession extends DefaultSession, Session {}
   
  const session: NewSession = {
    user: {
      name: 'a',
      email: 'b',
      id: 'a'
    }
  }
  
  // 参照できると思っていたけど、  session.user.idだけうまく参照できない。
  session.user.id
  session.user.name
  session.user.email
  session.user.image
  session.expires

NewSessionには以下のようなエラーが出ていました。

Interface 'NewSession' cannot simultaneously extend types 'DefaultSession' and 'Session'. Named property 'user' of types 'DefaultSession' and 'Session' are not identical.

ref: github.com

同じ名前のプロパティは継承できないんですね。変な勘違いをしていました。

以上です!