BFFとは何か。鍵を渡さず、札だけを持つ認証設計

BFF認証を、ホテルの鍵と引換札のたとえで整理します。アクセストークンをブラウザに持たせる方式と、httpOnly cookieでサーバーに預ける方式の違い、速さと安全性の見方、従来方式が今も生きる場面を説明します。

著者
岡崎 太
CTO / AIアーキテクト
公開日
読了時間
9分で読めます
Share

「BFF って、結局ブラウザがアクセストークンを持って毎回認証する方法ではないの?」

認証方式の話をしていると、この疑問がよく出ます。名前だけ聞くと、フロントエンドのためのバックエンドという意味は分かっても、実際に何が安全になり、何が速くなるのかは見えにくい。

この記事では、BFF 認証を「ホテルの鍵」と「引換札」のたとえで整理します。

先に結論を書くと、BFF は アクセストークンをブラウザに持たせないための設計です。ブラウザが持つのは、JavaScript から読めない httpOnly cookie のようなセッションの札。アクセストークンという鍵そのものは、サーバー側に預けます。

なお、この記事では praxis(フィールフロウの SaaS 製品)や FFID(FeelFlow ID Platform。フィールフロウ製品の管理基盤)という製品名は例として扱いますが、具体的な実装手順や社内詳細ではなく、公開できる設計の考え方に絞ります。

BFF には 2 つの文脈がある

BFF は Backend for Frontend の略です。

もともとは、Web、モバイル、TV など、フロントエンドごとに専用の薄いバックエンドを置き、それぞれの画面に合う形で API を集約するアーキテクチャパターンとして知られています。

一方、OAuth や Web 認証の文脈で BFF と言うと、少し意味が絞られます。ここでの BFF は、ブラウザアプリの代わりにサーバーが OAuth の処理を引き受け、アクセストークンやリフレッシュトークンをブラウザの JavaScript に直接触らせない構成です。

IETF OAuth Working Group の OAuth 2.0 for Browser-Based Apps draft でも、ブラウザベースアプリの OAuth 構成として BFF が整理されています。BFF は認可サーバーに対して confidential client として振る舞い、取得したトークンを cookie ベースのセッションに結びつけ、ブラウザへトークンを直接露出しない設計です。

この記事で扱うのは、この認証文脈の BFF です。

鍵を渡す方式と、札を渡す方式

ホテルで考えると分かりやすくなります。

従来のブラウザ保持方式は、チェックインしたお客さんに部屋の鍵を直接渡すホテルです。お客さん、つまりブラウザは、自分のポケットに鍵を入れて持ち歩きます。部屋に入るたび、自分で鍵を出して開けます。

この鍵がアクセストークンです。

問題は、ポケットが JavaScript から読める場所だった場合です。ページに悪意あるスクリプトが入り込む XSS が起きると、鍵そのものを持ち出される余地が生まれます。

一方、BFF 方式は、フロントで鍵を預かるホテルです。お客さんが持つのは鍵ではなく、引換札だけ。部屋に入りたいときは札を見せ、フロントのスタッフが裏側で鍵を使って代わりに開けます。

鍵を渡す方式と、BFF方式で札だけを渡す方式の違いを、ホテルのフロントにたとえて示した図

技術的に言うと、ブラウザが持つのは httpOnly cookie のようなセッション情報です。ブラウザはその cookie をリクエストに自動で付けますが、ページ上の JavaScript は cookie の中身を読み取れません。

ここが大事です。

BFF は「毎回ブラウザがアクセストークンを見せる方式」ではありません。むしろ逆です。アクセストークンをブラウザに持たせないために、サーバー側をフロントデスクとして置く方式です。

httpOnly cookie は、BFF を支える重要な部品です。

OWASP の Session Management Cheat Sheet でも、HttpOnly 属性は JavaScript から cookie を読ませないための重要な対策として説明されています。Auth.js も Session Strategies の中で、JWT セッションや database session の ID を HttpOnly cookie に保存する考え方を説明しています。Auth0 の Next.js SDK でも cookie 設定において httpOnly は常に true とされています。

ただし、httpOnly cookie だけで BFF になるわけではありません。

BFF の核心は、認可コードからトークンへの交換を、ブラウザではなくサーバーが担うことです。サーバーは client secret を安全に持てる confidential client として振る舞えます。ブラウザやモバイルアプリは secret を隠せない public client なので、同じ前提には立てません。

つまり、役割はこう分けて考えるとよいです。

部品 役割
サーバー側の token exchange 鍵そのものをブラウザに渡さない
httpOnly cookie ブラウザが持つ札を JavaScript から読ませない
Secure / SameSite / state 検証 cookie 利用時の別の攻撃面を塞ぐ
短命化 / ローテーション / サーバー側失効 盗まれた場合の被害時間を短くする

「安全ですか?」と聞かれたら、正確には「どの攻撃に対して安全か」を分けて答える必要があります。

httpOnly cookie が強いのは、ページ上の JavaScript による読み取りを防げる点です。XSS があっても、少なくとも cookie の値を document.cookie のような形で盗み出すことはできません。

ただし、XSS そのものを無効化するわけではありません。悪意あるスクリプトが同じブラウザ内で動いているなら、そのブラウザから認証済みリクエストを送ることはできます。cookie はブラウザが自動で付けるからです。

また、cookie 認証には CSRF の検討も必要です。だから BFF は httpOnly だけで完結するのではなく、Secure、SameSite、state 検証、CSRF 対策、短命なトークン、ローテーションなどを組み合わせます。

httpOnly cookie が守る範囲と、別途対策が必要な範囲を整理した図

セキュリティ設計では、「絶対安全か」よりも「どの被害をどこまで小さくできるか」が重要です。

httpOnly cookie は、ブラウザで取れる選択肢の中で、XSS によるトークン持ち出しのリスクを下げる強い部品です。ただし、XSS 対策、CSRF 対策、端末保護、セッション失効設計の代わりにはなりません。

札方式は遅くならないのか

ホテルのたとえで考えると、札方式は毎回フロントで鍵に交換してもらうので、鍵を自分で持つより遅そうに見えます。

この直感は半分正しいです。構成によっては、BFF は 1 ホップ増えます。ブラウザが外部 API を直接大量に呼ぶアプリなら、全部を自社サーバー経由にすることでサーバー負荷や遅延が増えることがあります。

ただし、praxis(フィールフロウの SaaS 製品)のように、もともと自社サーバーがページやデータの通り道になる Web アプリでは話が変わります。フロントデスクは最初から動線上にあります。鍵を持っていても、結局はフロントを通る構造です。

BFF で速くなる可能性があるのは、特にログイン時です。

従来の構成では、ブラウザ側で認可コードを受け取り、トークン交換を行い、その後にサーバー側セッションへ同期するような段取りが必要になることがあります。BFF では、認可コードを受け取ったサーバーがそのまま FFID(FeelFlow ID Platform。フィールフロウ製品の管理基盤)と通信し、セッションを作ります。ブラウザから見た往復が減り、処理の中心がサーバー間通信へ移ります。

ログイン時のブラウザ往復が、従来方式では多くなりやすく、BFF方式ではサーバー側へ寄ることを示した図

毎回の画面表示や API 利用では、ブラウザは cookie を送るだけです。サーバー側でセッションや署名を確認できるなら、毎回 FFID に問い合わせる必要はありません。課金状態や権限など、FFID でしか確認できない情報が必要な場面だけ、必要に応じて問い合わせればよい。

つまり、速度の議論は「BFF かどうか」だけでは決まりません。

大事なのは動線です。すでに自社サーバーが通り道なら、BFF は追加コストよりも、ログイン時の往復削減と認証処理の単純化が効く場合があります。逆に、自社サーバーを通らず外部 API を直接叩く設計なら、従来方式のほうが自然なこともあります。

従来方式が今も生きる場面

BFF は万能ではありません。

ブラウザがアクセストークンを持つ方式、つまり public client + PKCE が今も適している場面はあります。

PKCE(Proof Key for Code Exchange)は、ブラウザやモバイルアプリのように client secret を安全に隠せない public client 向けの追加確認です。ログイン開始時に一時的な合言葉を作り、認可コードをトークンへ交換するときに、同じ流れのリクエストだったことを確かめます。アクセストークンをブラウザに持たせない仕組みではなく、認可コードの横取りや取り違えを防ぐための安全策と考えると分かりやすいです。

たとえば、静的サイトや純粋な SPA では、そもそもフロントデスクとなる自社サーバーがありません。BFF のためだけにサーバーを新設するのは、目的に対して重すぎることがあります。

また、Google API や地図 API のように、ブラウザから外部 API を直接大量に呼ぶ構成では、トークンを持って直接アクセスしたほうが素直な場合があります。全部を BFF 経由にすると、通信経路もサーバー費用も増えます。

モバイルアプリ、デスクトップアプリ、CLI のように、ブラウザの cookie 機構を前提にできない環境もあります。この場合は、OS の Keychain や Keystore などにトークンを保管し、自分で送る設計が必要になります。

判断軸は、次の 3 つです。

問い BFF が自然になりやすい条件 従来方式が自然になりやすい条件
自社サーバーは既に通り道か Next.js などのサーバーが全体の入口になる 静的 SPA でサーバーがない
外部 API をブラウザから直接叩く必要があるか 自社サーバー経由で完結できる 外部 API を大量に直接呼ぶ
実行環境に cookie はあるか ブラウザ中心の Web アプリ モバイル、デスクトップ、CLI

praxis は、自社サーバーがアプリの入口になり、FFID が認証の中心にいる構成です。そのため、BFF へ寄せる判断が自然になります。逆に、FFID SDK がクライアント側モードを持ち続ける意味もあります。FeelFlow の他サービスが静的 SPA や別の実行環境を採るなら、そちらでは public client + PKCE が適する可能性があるからです。

生成AI時代に、なぜ認証の仕組みを知る必要があるのか

生成AIは、指示がなければ「それらしい実装」を選びます。けれど、その実装がどのリスクを下げ、どのリスクを残しているのかまでは、人間が問いを立てなければ見えません。

システムに 100% 安全はありません。ログインやセッションの仕組みも、通信、ブラウザ、サーバー、端末という複数の場所を通ります。大事なのは、危険をゼロにしたつもりになることではなく、どの情報をどこに置き、どの攻撃に備え、どのリスクを事業として受け入れるのかを理解することです。

BFF はそのための選択肢の一つです。鍵をブラウザに持たせず、札だけを持たせる。これは魔法ではありませんが、リスクの置き場所を変える設計です。

AI に実装を任せる時代だからこそ、人間は「何を守りたいのか」「どのリスクを避けたいのか」「どこまでを許容するのか」を言語化する必要があります。

まとめ

BFF 認証は、ブラウザが鍵を持って毎回見せる方式ではありません。

鍵、つまりアクセストークンはサーバーが預かります。ブラウザが持つのは、JavaScript から読めない札としての cookie です。ブラウザは札を自動で送る。サーバーは札を見て、必要なときだけ裏側で鍵を使う。

この構成により、アクセストークンがブラウザの JavaScript に直接載る窓を閉じられます。ログイン時の段取りもサーバー側へ寄せられるため、praxis のように自社サーバーがもともと通り道になっているアプリでは、速度面でも設計面でも合理的です。

ただし、httpOnly cookie だけで安全になるわけではありません。XSS、CSRF、端末侵害、セッション失効は別の論点として残ります。BFF は単一の魔法ではなく、サーバー側 token exchange、httpOnly cookie、Secure、SameSite、state 検証、短命化、ローテーションを組み合わせた設計です。

新しい方式が古い方式を置き換えるのではありません。

フロントデスクを持てるなら札。持てない、または外部 API へ直接行く必要があるなら鍵。

方式の優劣ではなく、アプリの動線に合わせて選ぶことが大事です。

参考