NextAuth.jsのセッションからAccessTokenを取得できるようにする。

一般的な話であるが、OAuth認証の基本的な仕組みを前提として確認する。OAuth認証を利用するWebアプリは、OIDCプロバイダから提供されたアクセストークンの正しさを、ユーザプロファイル情報の取得可否によって確認する。つまり、認証の過程においてWebアプリは、OIDCプロバイダのアクセストークンを取得している。この取得したアクセストークンを保持しておいて、OIDCプロバイダの提供するAPI呼び出しに使おう考えるのはごく自然なことである。

そういうわけで、本記事ではNextAuth.jsでの認証後、アクセストークンを取得する方法について扱う。 NextAuth.jsの仕組み上、アクセストークンはセッションに保存し、利用する際もセッションデータから取得することになる。

本記事で扱ったNextAuth.jsのバージョンは4.24.5である。過去記事でも検討したAutodeskのAPSをOIDCプロバイダとして利用して検証した。

ma38su.hatenablog.com

型情報の拡張

NextAuth.jsのSession型には、アクセストークンは含まれていない。そのため、型定義を拡張する必要がある。 とりあえず、以下のファイルを作成することで必要な型の拡張ができる。 (ここの細かい仕組みはよくわかっていない。)

/app/types/next-auth.d.ts

import { DefaultSession } from "next-auth";
import { JWT } from "next-auth/jwt";

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

declare module "next-auth/jwt" {
  interface JWT {
    accessToken?: string;
  }
}

認証処理の設定

callbacksに、sessionとjwtの処理を追加する。

/app/api/auth/[...nextauth]/option.ts

import { AuthOptions } from "next-auth";

...

function newAuthOptions() {
  return {
    providers: [
      AutodeskProvider({ ...  })
    ],
    callbacks: {
      async session(params) {
        const { session, token } = params;
        // JWTトークンのaccessTokenをセッションへコピーする。
        session.accessToken = token.accessToken;
        return session;
      },
      async jwt(params) {
        const { token, account } = params;
        if (account) {
          // サインイン時にアクセストークンをJWTに保存する。
          token.accessToken = account.access_token
        }
        return token
      },
    },
    ...
  } satisfies AuthOptions
}

export const options = newAuthOptions();

これで認証処理の設定はOK。アクセストークンはサインイン時にJWTに保存するので、テストする場合はサインインしなおす必要がある。

セッション情報の取得

サーバサイドでsessionを取得する場合は以下。

import { options } from "../auth/[...nextauth]/option";

export async function GET(req: Request) {
  const session = await getServerSession(options);
  ...
}

getServerSessionの引数には認証処理を設定したoptionsを渡さないとアクセストークンがセッションに含まれてこない。

クライアントサイドの場合はSessionProviderでWrapしたうえでuseSessionで取得する。 App Routerを利用している場合はuse clientが必須。

"use client"
import { SessionProvider } from "next-auth/react"
import { useSession } from "next-auth/react"

function App() {
  return <SessionProvider>
    <SessionView />
  </SessionProvider>
}

function SessionView() {
  const { data: session } = useSession()
  return <pre>{JSON.stringify(session)}</pre>
}

参考文献

公式に大体書いてある。

next-auth.js.org