🔒

React Server Actions 上でリクエストを認証する

2024/05/12に公開

はじめに

Next.js の App Router について理解を深めようと思い、公式の学習コンテンツをさらっていた。
https://nextjs.org/learn/dashboard-app

Chapter 15 にて認証を取り扱っていたが、クライアントサイドのケアしかされていなかったのが気にかかり、 Server Actions でのケアの方法を調べた。

結論、 Next.js の API を使うなら import { cookies, headers } from 'next/headers'; を利用して任意の cookie や header にアクセスすればよい。
上記のコンテンツでインストールしている NextAuth.js の API を使うなら import { auth } from '@/auth'; を利用してセッション情報を取ればよい。

Server Actions とは

Server Actions 自体は Next.js 非依存の React の機能のひとつ。
サーバー上で実行される非同期関数を定義し、コンポーネントから呼ばせることができる。
https://ja.react.dev/reference/rsc/server-actions

言葉の通りだが、フレームワークを使う開発者目線では、「サーバー上で実行させたい関数」をコード上定義し、単にそれを React コンポーネントの prop へ渡すだけで良い。
フォーム送信などの画面上でのユーザーの操作に基づいて、定義した関数の実行を命じるリクエストがサーバーへ飛ぶことになる。

特に、上掲の Next.js の学習コンテンツにおいては <form>action attribute へ関数を渡して Server Actions を活用する例を学べる。
https://ja.react.dev/reference/react-dom/components/form

そもそも Server Actions に認証は必要か?

Next.js の公式ドキュメントからの引用になるが、 Server Actions はパブリックな API と同様にセキュリティ面のケアが必要となる。
従って、閲覧や操作を制限したい Server Actions においては、適切に認証認可のためのコードを追加する必要がある。

Treat Server Actions with the same security considerations as public-facing API endpoints, and verify if the user is allowed to perform a mutation.

https://nextjs.org/docs/app/building-your-application/authentication

Chrome の DevTools の Network タブから Server Actions 呼び出しのリクエストをコピーして、認証されていない環境から実行してみると、挙動を確認しやすい。

Next.js の API を使う場合

Next.js が提供している next/headers package から cookies もしくは headers 関数を import して中身を展開すればよい。
自前で cookie へセッション情報を詰める認証機構を持っていたり、何らかの方法で認証用のヘッダー値を挿入したりしている場合はこれで対応できる。

// actions.ts
'use server';

import { cookies } from 'next/headers';

export const mutate = async () => {
  try {
    const { isAuthed } = await customSessionConfirmFunction(
      cookies().get('my_session'),
    );
    if (!isAuthed) {
      return { message: 'Unauthenticated.' };
    }
  } catch (error) {
    return { message: 'Failed to Confirm Session.' };
  }

  // do something...
};

cookies().getAll().forEach()headers().forEach() を使うと、実際にどんな値が入っているのかを細かく確認できる。

NextAuth.js の API を使う場合

上掲の学習コンテンツでインストールしていた NextAuth.js を利用する場合は、自身で定義したファイルから auth 関数を引いてくる必要がある。

現在のメジャーバージョンである v4 では getServerSession 関数が定義されており、基本的にこれを活用する方針であった。
https://next-auth.js.org/configuration/nextjs

しかし学習コンテンツ内でインストールしていた v5 (beta) の場合は auth() を利用するよう仕様変更が入っている。
https://authjs.dev/getting-started/migrating-to-v5

// auth.ts
import NextAuth from 'next-auth';

export const { 
  auth, // これを使う
} = NextAuth({
  // 設定を色々書く
});

Server Actions 側のコードはこんな感じになる。

// actions.ts
'use server';

import { auth } from '@/auth';

export const mutate = async () => {
  try {
    const session = await auth();
    if (!session?.user) {
      return { message: 'Unauthenticated.' };
    }
  } catch (error) {
    return { message: 'Failed to Confirm Session.' };
  }

  // do something...
};

まとめ

  • React の Server Actions ではリクエストが認証・認可されていることを適切に確認する必要がある
  • フレームワークやライブラリが用意してくれている API を適切に用いることで、従来サーバーで定義していた API と同様に確認ができる

Discussion