Next.js は BFF になれる
Next.js App Router は、フロントエンドだけでなくサーバ側の処理も同じプロジェクトに持てます。
そのため、ブラウザと外部APIの間に立つBFFとして使いやすいです。
Browser -> Next.js -> External API
認証では、ブラウザには HttpOnly Cookie を持たせ、Next.jsサーバ側がJWTやOAuth access tokenを使って外部APIを呼ぶ構成にできます。
BFF に必要な役割
BFFには、主に次の役割があります。
| 役割 | Next.js の機能 |
|---|---|
| 認証済みページの表示 | Server Components |
| フォーム送信、更新処理 | Server Actions |
| API中継 | Route Handlers |
| 未認証ユーザーの早期リダイレクト | Middleware |
| Cookie読み取り | cookies()、認証ライブラリ |
このため、Next.jsはBFFの実装単位として自然に使えます。
Server Components でデータ取得する
Server Components はサーバ側で実行されます。ブラウザではなくサーバでセッションを読み、APIを呼べます。
import { redirect } from "next/navigation";
import { auth } from "@/auth";
export default async function DashboardPage() {
const session = await auth();
if (!session) redirect("/login");
const orders = await fetchOrdersForUser(session.user.id);
return <OrderList orders={orders} />;
}
この構成では、ブラウザにアクセストークンを渡す必要がありません。
Route Handlers で API 中継する
Route Handlers を使うと、Next.js内にAPIエンドポイントを作れます。
import { NextResponse } from "next/server";
import { auth } from "@/auth";
import { getAccessToken } from "@/lib/server/token";
export async function GET() {
const session = await auth();
if (!session) {
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
}
const accessToken = await getAccessToken();
const res = await fetch("https://api.example.com/orders", {
headers: { Authorization: `Bearer ${accessToken}` },
});
return NextResponse.json(await res.json());
}
ブラウザは /api/orders を呼ぶだけです。外部APIのトークンはサーバ側にあります。
Server Actions で更新処理を行う
Server Actions は、フォーム送信などの更新処理をサーバ側関数として書ける機能です。
"use server";
import { auth } from "@/auth";
import { revalidatePath } from "next/cache";
export async function createOrder(formData: FormData) {
const session = await auth();
if (!session) throw new Error("Unauthorized");
await createOrderOnApi({
userId: session.user.id,
title: String(formData.get("title")),
});
revalidatePath("/dashboard/orders");
}
更新処理がサーバ側にあるため、ブラウザにAPIトークンを持たせずに済みます。
Middleware は最終防衛線ではない
Middleware は、未認証ユーザーを早めにログイン画面へ飛ばす用途に便利です。
import { auth } from "@/auth";
export default auth((req) => {
if (!req.auth && req.nextUrl.pathname.startsWith("/dashboard")) {
return Response.redirect(new URL("/login", req.url));
}
});
ただし、Middlewareだけに認可を任せてはいけません。matcher漏れ、API直叩き、将来の構成変更で抜け道ができる可能性があります。
最終的な認証・認可チェックは、Server Component、Server Action、Route Handlerの中でも行います。
注意: Middleware はUX改善と早期リダイレクトの層です。認可の本体は各サーバ処理の内部に置きます。
Next.js でも BFF にならない構成
Next.jsを使っていても、次のような構成ではBFFとは言いにくくなります。
output: "export"で静的書き出ししている- ほぼすべてが
"use client"コンポーネント - ブラウザから外部APIを直接
fetchしている - access token を localStorage に保存している
この場合、Next.jsを使っていてもSPA時代のトークン問題に戻ります。
まとめ
Next.js App Router は、BFF構成と相性がよいです。
- Server Components でサーバ側データ取得ができる
- Server Actions で更新処理をサーバ側に置ける
- Route Handlers でAPI中継ができる
- ブラウザにJWTやaccess tokenを渡さない設計にしやすい
- Middlewareだけに認可を任せない
"use client"中心で外部APIを直接呼ぶならBFFではない
参考リソース
- 公式ドキュメント - Next.js はなぜ BFF と相性がいいのか を確認するための一次情報