Skip to content

FAPI 2.0 入門

FAPI(Financial-grade API)は OpenID Foundation が策定する OAuth 2.0 + OIDC のセキュリティプロファイル群です。基盤となる仕様が許している任意性のうち、本番環境で攻撃に使われてきたものを 取り除いた 内容になっています。

もともとは Open Banking 向け — 英国・豪州・ブラジルの規制当局が銀行とフィンテック間の OAuth に FAPI 相当を要求しています。最近は医療、政府デジタル ID など、「RFC に従っています」だけでは監査が通らない領域にも採用が広がっています。

このページで触れる仕様

なぜ「OIDC + ベストプラクティス」ではなくプロファイルなのか

OIDC と OAuth 2.0 では多くの選択肢が任意のままです:

  • authorize 要求はクエリ文字列のまま流せる
  • redirect_uri は部分一致でもよい
  • 署名アルゴリズムに RS256noneHS256 を含められる
  • クライアント認証に client_secret_basic(長寿命の共有秘密)を使える

これらの「任意性」はそれぞれ過去に CVE 級の脆弱性を生み出してきました。

プロファイル は「この deployment では選択肢を固定する」という契約です。FAPI 2.0 は安全な部分集合を選び、それ以外を禁じます。これにより適合確認が「議論」ではなく「チェックリスト」になります。

FAPI 1.0 と FAPI 2.0

FAPI 1.0("Read-Only" / "Read-Write" の 2 バンド)への参照を見かけることもあります。FAPI 2.0 はその後継 — シンプルで、形式検証された脅威モデルを持ち、認証取得もしやすくなっています:

FAPI 1.0(依然現役)FAPI 2.0
バンドRead-Only / Read-WriteBaseline / Message Signing
authorize 要求の経路任意の request JWTPAR 必須
送信者制約mTLS または holder-of-keyDPoP または mTLS 必須
response_typecode id_token(hybrid)も許可code のみ
アルゴリズムリストmetadata でネゴ固定 allow-list

go-oidc-provider は FAPI 2.0 を対象にしており、FAPI 1.0 は対象外です。

Baseline と Message Signing

FAPI 2.0 は 2 段構成です。

Baseline — 必須要件の最低ライン

Pushed Authorization Requests(PAR)、PKCE、DPoP または mTLS、ES256 / PS256 署名、redirect_uri の完全一致、private_key_jwt / mTLS でのクライアント認証。いずれの FAPI 2.0 deployment にも求められる最低水準 です。

Message Signing — 非否認性

Baseline に加えて: JAR(authorize 要求自体を署名 JWT にする)、JARM(authorize 応答も署名する)、DPoP nonce 必須、RS 側の応答署名。すべての要求・応答が暗号学的に発信元へ紐づくため、非否認性(nonrepudiation)が確保されます。

UK Open Banking と Brazil Open Insurance は Message Signing を必須化しています。

各略号が実際に何をしているか

PAR — Pushed Authorization Request (RFC 9126)

古典的な OAuth フローでは、RP が /authorize?... の URL を組み立て、すべてのパラメータをクエリ文字列に乗せてブラウザにリダイレクトさせます。間に挟まる主体(ブラウザ拡張、中継 proxy、Referer 漏洩、サーバログなど)はパラメータを見られます。

PAR は、RP がまずパラメータを OP の /par エンドポイントに server-to-server で直接 POST(クライアント認証付き)します。OP は短寿命の request_uri(例: urn:ietf:params:oauth:request_uri:abc...)を返します。ブラウザは /authorize?request_uri=urn:...&client_id=... にリダイレクトされ、OP は内部で元のパラメータを引き当てます。

結果: 機微なパラメータがブラウザを通らない。

JAR — JWT-Secured Authorization Request (RFC 9101)

PAR は「パラメータが OP に機密で届く」ことを保証します。JAR は 「正規の RP から来た」ことを OP が暗号学的に検証できる ようにします — パラメータは RP の秘密鍵で署名された JWT として渡され、OP は登録済みの公開鍵で署名を検証します。

PAR + JAR の組み合わせで、authorize 要求の server-to-server 配送発信元の暗号学的認証 の両方が手に入ります。

JARM — JWT-Secured Authorization Response Mode

JAR の応答版です。OP は authorize 応答codestateiss など)を JWT に署名して返し、RP が署名を検証します。これにより「OP が確かにこの code を私に発行した」という非否認性が得られます。

FAPI 2.0 Message Signing で必須。

DPoP / mTLS — 送信者制約

発行された access token を、正規クライアントが保有する鍵にバインドします。トークンが漏れても鍵がなければ使えません。仕組みは 送信者制約 を参照。

ES256 / PS256 — なぜ RS256 ではないのか

RS256(RSA-SHA256、PKCS#1 v1.5 パディング)は padding-oracle 攻撃や鍵混同攻撃に対して構造的に脆弱です。OIDC Core では今も許容されていますが、FAPI 2.0 では禁じられています。PS256(RSA-PSS)と ES256(P-256 上の ECDSA)が安全な代替です。go-oidc-provider は FAPI プロファイル下で ES256 / EdDSA / PS256 を受理し、RS256 はサーフェスから外します。

go-oidc-provider での 1 行有効化

go
import (
  "github.com/libraz/go-oidc-provider/op"
  "github.com/libraz/go-oidc-provider/op/profile"
)

op.New(
  /* 必須オプション */
  op.WithProfile(profile.FAPI2Baseline),
)

WithProfile は次をまとめて行います:

  1. feature.PAR / feature.JAR / feature.DPoP を自動有効化。
  2. token_endpoint_auth_methods_supported を FAPI allow-list(private_key_jwttls_client_authself_signed_tls_client_auth)と交差。
  3. ID Token 署名 alg を ES256 / PS256 にロック、RS256 での新規発行を拒否。
  4. redirect_uri の完全一致を強制。

プロファイルと矛盾するオプションを後から重ねると op.New が起動を拒否します — partial-FAPI な構成がレビューを抜けて本番に出ることはありません。

Message Signing にしたい場合は profile.FAPI2Baselineprofile.FAPI2MessageSigning に差し替えるだけ。Conformance suite は両プランを検査します(OFCS 適合状況)。

続きはこちら