Skip to content

認証アーキテクチャ: BFF Proxy パターン

設計判断

トークン管理を BFF 側に完全移行する BFF Proxy パターン を採用する。

観点従来方式(JavaScript 変数)BFF Proxy パターン(採用)
Access Token の保存場所ブラウザメモリ(JavaScript 変数)BFF サーバーサイドセッション
XSS リスクJavaScript から Access Token にアクセス可能ブラウザに JWT が存在しない
ブラウザに渡すものAccess Token + Refresh Token (Cookie)HttpOnly Session Cookie のみ
トークンリフレッシュブラウザが Refresh Token を送信BFF 内部で自動実行
SSO/OIDC 統合フロントエンドが OIDC フローを処理BFF がリレーパーティとして処理

フロー概要

POST /auth/login (credentials)認証リクエストAccess Token + Refresh Tokenセッション作成 (JWT + Refresh Token 保存)Set-Cookie: session_id (HttpOnly, Secure, SameSite=Strict)API リクエスト + Session Cookieセッション検証 → JWT 取得Access Token の有効期限確認API レスポンスブラウザには JWT が存在しない残り2分未満なら先行リフレッシュブラウザ (SPA)BFF認証サーバーセッションストア
POST /auth/login (credentials)認証リクエストAccess Token + Refresh Tokenセッション作成 (JWT + Refresh Token 保存)Set-Cookie: session_id (HttpOnly, Secure, SameSite=Strict)API リクエスト + Session Cookieセッション検証 → JWT 取得Access Token の有効期限確認API レスポンスブラウザには JWT が存在しない残り2分未満なら先行リフレッシュブラウザ (SPA)BFF認証サーバーセッションストア
属性理由
HttpOnlytrueJavaScript からのアクセスを防止(XSS 対策)
SecuretrueHTTPS 通信でのみ送信
SameSiteStrictクロスサイトリクエストでの送信を防止(CSRF 基本対策)
Path/全ポータルで共有
Max-Age7日Refresh Token と同期

トークンリフレッシュ

BFF はリクエスト処理時に Access Token の残り有効期間を確認し、残り2分未満 であれば Refresh Token を用いて事前にリフレッシュを実行する。

  • 先行リフレッシュ: リクエスト処理のレイテンシに影響しないよう、リフレッシュ対象のセッションを非同期で更新する。リフレッシュ中は旧 Access Token が引き続き有効
  • Refresh Token ローテーション: リフレッシュのたびに Refresh Token も新しいものに置き換える(旧トークンは即時無効化)
  • リフレッシュ失敗: Refresh Token が無効化されている場合(管理者による強制ログアウト等)、セッションを破棄し 401 Unauthorized を返却。SPA はログイン画面にリダイレクト

ログアウトフロー

POST /auth/logout + Session Cookieセッション取得 → Refresh Token 取得Refresh Token 無効化OKセッション削除Set-Cookie: session_id="" (削除)ログイン画面にリダイレクトブラウザ (SPA)BFF認証サーバーセッションストア
POST /auth/logout + Session Cookieセッション取得 → Refresh Token 取得Refresh Token 無効化OKセッション削除Set-Cookie: session_id="" (削除)ログイン画面にリダイレクトブラウザ (SPA)BFF認証サーバーセッションストア

SSO/OIDC 統合(→ SR-012

BFF が SAML/OIDC のリレーパーティ(RP)として機能し、IdP との認証フローを処理する。ブラウザからは通常のセッション Cookie アクセスと同じ体験を提供する。

alt [SAML 2.0][OIDC]opt [JIT プロビジョニング]SSO ログイン開始IdP へリダイレクト認証リクエストユーザー認証SAML Assertion / Authorization Codeコールバック (Assertion / Code)XML 署名検証 + Assertion 検証Authorization Code → Token 交換 (PKCE)ID Token + Access TokenIdP トークン → TASHIKA JWT に変換IdP クレームからユーザー自動作成セッション作成Set-Cookie: session_id (HttpOnly)ブラウザ (SPA)BFF (RP)IdP (SAML/OIDC)セッションストア
alt [SAML 2.0][OIDC]opt [JIT プロビジョニング]SSO ログイン開始IdP へリダイレクト認証リクエストユーザー認証SAML Assertion / Authorization Codeコールバック (Assertion / Code)XML 署名検証 + Assertion 検証Authorization Code → Token 交換 (PKCE)ID Token + Access TokenIdP トークン → TASHIKA JWT に変換IdP クレームからユーザー自動作成セッション作成Set-Cookie: session_id (HttpOnly)ブラウザ (SPA)BFF (RP)IdP (SAML/OIDC)セッションストア
  • SAML 2.0: BFF が SP として Assertion を受信・検証。XML 署名検証、NotBefore/NotOnOrAfter によるリプレイ防止
  • OIDC: Authorization Code Flow + PKCE 必須。BFF が Authorization Code を Token に交換
  • IdP トークンの扱い: IdP の Access Token / ID Token は BFF 内部で保持。TASHIKA 独自の JWT に変換してセッションに保存。IdP トークンの有効期間と TASHIKA セッションは独立管理
  • JIT プロビジョニング: SSO 初回ログイン時にユーザーが TASHIKA に存在しない場合、IdP のクレームから自動作成。SCIM との併用時は SCIM を優先
  • Single Logout (SLO): SAML LogoutRequest / OIDC Front-Channel Logout に対応。BFF セッションと Refresh Token を連動して無効化

セッションストア

方式特性採用時期
PostgreSQL(Refresh Token テーブル流用)既存インフラで完結。トランザクション整合性。Refresh Token と同一テーブルで管理可能MVP
分散キャッシュ(Redis 等)高スループット。セッション数が大量になった場合に有効スケールアウト時に検討

MVP ではセッションデータを既存の Refresh Token テーブルに列追加する形で管理する。セッション数は同時セッション制限(ユーザーあたり最大3)により制御されるため、PostgreSQL で十分なパフォーマンスを確保できる。

CSRF 保護

SameSite=Strict Cookie を基本防御としつつ、Double Submit Cookie パターン を追加する:

  1. BFF がセッション作成時に CSRF トークン(ランダムな UUID)を生成
  2. CSRF トークンを 非 HttpOnly の Cookiecsrf_tokenSameSite=Strict; Secure)としてブラウザに設定
  3. SPA は状態変更リクエスト(POST/PUT/PATCH/DELETE)時に、Cookie から読み取った CSRF トークンを X-CSRF-Token ヘッダーに付与
  4. BFF は Cookie 内の CSRF トークンとヘッダーの値を照合
Cookie: session_id=xxx; csrf_token=yyy
X-CSRF-Token: yyy

GET リクエスト(冪等)には CSRF トークン検証を適用しない。

→ 満たす要件: SR-002 認証要件SR-005 セキュリティポリシーSR-012 SSO・フェデレーション