Skip to content

ユースケース — FAPI 2.0 Message Signing ​

profile.FAPI2MessageSigning は、FAPI 2.0 Baseline に 3 つの署名付きメッセージ(認可リクエスト、認可レスポンス、introspection レスポンス)を加えたものです。Baseline のページに挙げた内容はすべてそのまま当てはまります。PAR、PKCE、DPoP または mTLS、private_key_jwt または証明書によるクライアント認証、クライアント assertion の aud を issuer だけにすること、ローテーションしないリフレッシュトークンです。このページが扱うのは、そこから変わる点だけです。

go
op.New(
  /* FAPI2Baseline と同じオプション */
  op.WithProfile(profile.FAPI2MessageSigning),
  op.WithDPoPNonceSource(nonces), // DPoP が有効な間は必須。下記を参照
)
このページで触れる仕様

プロファイルが入れるもの、利用者が用意するもの ​

Message Signing は、Baseline の表の内容をすべて含み、次の行が加わります。

プロファイルが入れるもの利用者が用意するもの
必須の JAR: /par と /auth へのリクエストはすべて署名付き request object を伴うすべてのクライアントの鍵セット(JWKS または JWKSURI)と、PS256・ES256・EdDSA で署名するクライアント
JARM: /auth のレスポンスは署名付き JWTOP の JWKS で JARM レスポンスを検証できるクライアント
署名付き introspection: /introspect は RFC 9701 の JWT で応答リソースサーバが呼ぶ場合は feature.Introspect、署名付き応答を検証するリソースサーバ(API を保護する)
DPoP が有効な間は DPoP nonce のチャレンジnonce source: レプリカ 1 台なら op.NewInMemoryDPoPNonceSource、複数なら op/storeadapter/redis の Store.DPoPNonceSource など共有できるもの

Baseline の表もこの表も、すべてのレプリカで共有するストアと、プロキシの背後では op.WithTrustedProxies(mTLS ならさらに op.WithMTLSProxy と op.WithMTLSRootCAs)を前提にしています。動かせる版は examples/54-fapi2-message-signing です。

チェックリスト ​

署名付き request object が必須になる ​

/par と /auth へのリクエストは、すべて署名付きの JAR request object を伴う必要があります。Baseline は request object を受け付けつつ通常のパラメータも受け付けますが、Message Signing では署名付きオブジェクトのないリクエストを拒否します。プロファイルが feature.JAR を有効にするので、必要な作業はクライアント側とクライアント登録だけです。

  • OP が request object を検証できる鍵セット(JWKS または JWKSURI)を、クライアントに登録します。private_key_jwt のクライアントなら、すでに持っています。
  • クライアントの署名は PS256、ES256、EdDSA のいずれかで、RS256 は拒否されます。
  • request object は署名されていない query / form パラメータとマージされず、置き換えます。認可パラメータはすべて署名付きオブジェクトの中に入れてください。
  • オブジェクトの iat は最大 60 分前まで許容されます(profile.MaxRequestObjectAge)。nbf と exp の検証も引き続き行われます。

認可レスポンスは JARM になる ​

/auth のレスポンスは、すべて OP の有効な署名鍵で署名した JARM の JWT で包まれます。プロファイルが feature.JARM を有効にするので、ほかに設定するものはありません。RP は OP の JWKS で JWT を検証し、その claim から code、state、iss を読み取ります。JARM のレスポンスを処理できないクライアントは、このプロファイルを使えません。

introspection レスポンスが署名される ​

/introspect をマウントしている場合、成功レスポンスはすべて RFC 9701 の JWT 形式になり、呼び出し側が送った Accept ヘッダやクライアントのメタデータにかかわらず、OP の有効な鍵で署名されます。プロファイル自体はこのエンドポイントをマウントしません。リソースサーバが呼び出すなら feature.Introspect を有効にし、呼び出し側が署名付き JWT のレスポンスを受け付けて JWKS で検証できることを確認してください。

DPoP が有効な間は DPoP nonce source が必須になる ​

DPoP が有効で nonce source が未設定だと、op.New は WithProfile(profile.FAPI2MessageSigning) requires a DPoP nonce source because DPoP is active というエラーで失敗します。DPoP が有効になるのは、feature.DPoP を指定した場合と、feature.DPoP も feature.MTLS も指定しなかったためにプロファイルが DPoP を自動で選んだ場合です。送信者制約に feature.MTLS を選んだ OP は、nonce source を必要としません。

この要件は本ライブラリのプリセットによるものです。最終版の FAPI 2.0 Security Profile と Message Signing 仕様では DPoP nonce は任意なので、適合の主張はこの要件に左右されません。source を設定すると、/token、/par、/userinfo は、受理できる nonce を含まない proof に use_dpop_nonce と新しい DPoP-Nonce ヘッダで応答します(DPoP nonce フロー)。profile.FAPICIBA も同じ要件を持ちます。

複数レプリカでは nonce source を共有する ​

op.NewInMemoryDPoPNonceSource はプロセス内で閉じているため、あるレプリカが発行した nonce は別のレプリカでは通用しません。op/storeadapter/redis の Redis source を使ってください。

go
nonces, err := redisStore.DPoPNonceSource(time.Minute)
if err != nil {
  log.Fatal(err)
}
op.WithDPoPNonceSource(nonces)

store のキー prefix を共有するレプリカは、nonce の状態も共有します。障害時の挙動は 複数インスタンス運用 にあります。

変わらないもの ​

クライアント認証の選択肢、aud の規則、ローテーションしないリフレッシュトークン、アクセストークン 10 分の上限、WithPARTTL の上限、redirect_uri の完全一致、TLS まわりの判断(プロキシの扱い、op.FAPITLSConfig に必要な RSA 証明書)は Baseline と同じです。これらは Baseline のページを参照してください。

次に読む ​

  • FAPI 2.0 Baseline — このページの土台になるプロファイル。
  • DPoP nonce フロー — nonce のやり取りと組み込み手順。
  • FAPI 2.0 入門 — 署名付きメッセージそれぞれの目的。
  • JARM — 署名付き認可レスポンスの組み立てと検証。