React Server Actions 上でリクエストを認証する
はじめに
Next.js の App Router について理解を深めようと思い、公式の学習コンテンツをさらっていた。
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 の機能のひとつ。
サーバー上で実行される非同期関数を定義し、コンポーネントから呼ばせることができる。
言葉の通りだが、フレームワークを使う開発者目線では、「サーバー上で実行させたい関数」をコード上定義し、単にそれを React コンポーネントの prop へ渡すだけで良い。
フォーム送信などの画面上でのユーザーの操作に基づいて、定義した関数の実行を命じるリクエストがサーバーへ飛ぶことになる。
特に、上掲の Next.js の学習コンテンツにおいては <form>
の action
attribute へ関数を渡して Server Actions を活用する例を学べる。
そもそも 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.
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
関数が定義されており、基本的にこれを活用する方針であった。
しかし学習コンテンツ内でインストールしていた v5 (beta) の場合は auth()
を利用するよう仕様変更が入っている。
// 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