🐱

Next.jsのサーバーサイドでユーザー認証しながらバックエンドのリソースにアクセスするためのメモ

2022/10/04に公開約2,600字

getServerSideProps でのセッション情報取得

SSR のタイミングでバックエンドからデータ取得するにあたり、認証してないクライアントからのリクエストごとにバックエンドのリソースにアクセスをしたくないので getServerSideProps 実行時に Next Auth でセッション情報を取得する方法を探してみた。

結果的に「unstable_getServerSession」なる機能が試験的に実装されていたのでとりあえずそれを使ってみた。
https://next-auth.js.org/configuration/nextjs#unstable_getserversession

実装方法(2022/10/4 時点)

pages/api/auth/[...nextauth].ts の修正

基本的な実装はこのような形になっているのを

import NextAuth from "next-auth";
/* import some providers */

export default NextAuth({
  /* config */
});

設定の中身(NextAuthOptions)をエクスポートする。

import NextAuth from "next-auth";
import type { NextAuthOptions } from "next-auth";

export const authOptions: NextAuthOptions = /* config */
export default NextAuth(authOptions);

getServerSideProps を実装

サーバーサイドで認証を行いたいエンドポイントの getServerSideProps を実装する。

import type { GetServerSidePropsContext } from "next";
import { unstable_getServerSession } from "next-auth";
import { authOptions } from "../pages/api/auth/[...nextauth]";

export async function getServerSideProps(context: GetServerSidePropsContext) {
  const session = await unstable_getServerSession(
    context.req,
    context.res,
    authOptions
  );

  if (session) {
    return { props: /* Authenticated Props */ };
  } else {
    return { props: /* Not authenticated Props */ };
  }
}

実装例

試しに CosmosDB のチュートリアルになっている ToDoList から Items を認証時のみ引っ張ってこようとするとこうなる

import type { NextPage, GetServerSidePropsContext } from "next";
import { unstable_getServerSession } from "next-auth";
import { CosmosClient } from "@azure/cosmos";
import { authOptions } from "../pages/api/auth/[...nextauth]";

type Item = {
  id: string;
  category: string;
  name: string;
  description: string;
  isComplete: boolean;
};

type Props = {
  items?: Item[];
};

export async function getServerSideProps(
  context: GetServerSidePropsContext
): Promise<{ props: Props }> {
  const session = await unstable_getServerSession(
    context.req,
    context.res,
    authOptions
  );

  if (session) {
    const endpoint = process.env.COSMOS_DB_URI;
    const key = process.env.COSMOS_DB_KEY;
    const client = new CosmosClient({ endpoint, key });
    const database = client.database("ToDoList");
    const container = database.container("Items");
    const { resources: items } = await container.items
      .query({
        query: "SELECT * from c",
      })
      .fetchAll();
    return { props: { items } };
  } else {
    return { props: {} };
  }
}

const Page: NextPage<Props> = ({ items }) => {
  return <>/* implement components */</>;
};

export default Page;
GitHubで編集を提案

Discussion

ログインするとコメントできます