OFCS 適合状況
go-oidc-provider は OpenID Foundation Conformance Suite (OFCS) に対して回帰検査されています。ハーネスはソースリポジトリの conformance/ に置かれており、9 つの OFCS プランを準備します。本ページのベースラインは、2026-11-04 にライブラリのコミット 9e8d5153 で取得した run で、cmd/op-demo インスタンスに対して end-to-end で実行しました。
個人開発、認証取得は無し
これは個人開発者が維持するプロジェクトです。OpenID Foundation 会員費は支払っておらず、形式的な OIDC 認証は取得していません。本ページの数値は、下に示すプラン集合の再現可能なスナップショットです。これは有償の OpenID Foundation 認証の代替ではなく、そのように引用しないでください。
この snapshot が検査する範囲
| Plan | カバー範囲 | プロファイル |
|---|---|---|
oidcc-basic-certification-test-plan | 認可コード + PKCE、ID トークン、UserInfo、refresh、discovery | OIDC Core 1.0 |
oidcc-config-certification-test-plan | discovery ドキュメントと公開 JWKS の形 | OIDC Core 1.0 — Discovery |
oidcc-dynamic-certification-test-plan | 動的クライアント登録と、そこで登録したクライアントによる認可コードフロー | OIDC Core 1.0 — Dynamic Registration |
oidcc-formpost-basic-certification-test-plan | basic プランを response_mode=form_post で再実行 | OIDC Core 1.0 — form_post |
oidcc-rp-initiated-logout-certification-test-plan | /end_session、id_token_hint、post_logout_redirect_uri | RP-Initiated Logout 1.0 |
oidcc-backchannel-rp-initiated-logout-certification-test-plan | RP 起点のログアウトと、登録済みバックチャネル URI への logout_token 送達 | Back-Channel Logout 1.0 |
fapi2-security-profile-final-test-plan | + PAR、送信者制約付きアクセストークン(DPoP)、厳格 alg list、redirect_uri 完全一致 | FAPI 2.0 Security Profile Final(Baseline) |
fapi2-message-signing-final-test-plan | + JAR(署名 authorization request)、JARM(署名 authorization response) | FAPI 2.0 Message Signing Final |
fapi-ciba-id1-test-plan | Client-Initiated Backchannel Authentication(poll mode)、mTLS バインドトークン | FAPI-CIBA |
fapi2-security-profile-final と fapi2-message-signing-final は、スイートが提供する FAPI 2.0 Security Profile Final と Message Signing Final の plan です。profile.FAPI2Baseline と profile.FAPI2MessageSigning では、OP はクライアントアサーションの aud として自身の issuer だけを単一の文字列で受け付け、refresh token をローテーションしません(Final §5.3.2.1)。この結果はスイートに対する回帰実行であり、認証ではありません。
最新 baseline
- PASSED20177.6%
- REVIEW3814.7%
- SKIPPED145.4%
- 未判定20.8%
- FAILED41.5%
- WARNING00.0%
FAILED と未判定の module はすべてレビュー済みの release exclusion です — 原因は 5 つで、いずれも理由と期限を記録しています。
スナップショットの状態
上のバーは 9 plan 全体の raw 結果で、OFCS release-v5.3.4 に対して実行したものです。JSON artifact は conformance/baselines/ 配下のローカル・gitignore 対象ファイルです。make conformance-release-verify はこの run を blocker 0 と判定しました。raw failure はすべて conformance/release-exclusions.json のレビュー済み・期限付きエントリと、未判定の module は証跡付きのエントリと、REVIEW と SKIPPED の module はレビュー済みのルールと照合されています。この判定は OIDC 認証ではありません。
FAILED 4 件の理由
FAILED と未判定の module は、すべて 5 つの原因のいずれかに帰着します。うち 2 つは OP の現在の設計判断で、1 つは suite が拒否する登録時の挙動、残る 2 つはヘッドレス実行の限界です。いずれも conformance/release-exclusions.json に担当者と期限付きで記録されています。
dynamic の certification プロファイルは、id_token と token id_token のレスポンスタイプおよび implicit grant も要求します。本 OP は OAuth 2.0 Security BCP の推奨どおり認可コードフローだけを提供するため、dynamic プランの discovery 検証は response types と grant types の条件で失敗します。同じ module の署名アルゴリズムの検証は、RS256 の OP に対してプランを実行すれば通ります。
oidcc-userinfo-rs256 は、UserInfo 暗号化なしで userinfo_signed_response_alg=RS256 のクライアントを登録します。動的登録は invalid_client_metadata を返します。OP が署名付き UserInfo の形を返すのは、登録値ではなく Accept: application/jwt を付けたリクエストに対してだからで、module は assertion に到達しません。原因はアルゴリズムではありません。同じ登録は ES256 でも拒否され、op.WithSigningAlgorithm(op.AlgRS256) で構築した OP は RS256 の UserInfo を発行します。
本 OP は backchannel_logout_session_supported: false を広告し、sid ではなく subject 単位でログアウトします。このメタデータは仕様上 optional ですが、この certification module は無条件に true を要求し、プラン残りも同じ assertion で中断します。sid 単位のセッションスコープログアウトは現在有効化しておらず、subject 単位は fail-secure 側の既定です。バックチャネルログアウト
oidcc-server-rotate-keys は「署名鍵をローテーションしてから Start を押す」ことを人間に要求します。本ライブラリは鍵束を op.New の時点で確定するため、実運用でのローテーションは provider の作り直しになり、プランで登録済みのクライアントを保持している in-memory store が失われます。OP が提供する内容自体には影響がなく、JWKS は設定済みの鍵をすべて公開しています。鍵ローテーション
oidcc-request-uri-signed-rs256 は、suite の自己署名証明書で提供されるホストに request object を公開します。OP は conformance CA を JWKS fetcher の transport にだけ入れており、request_uri の fetcher には入れていません。そのため /authorize は redirect 前に invalid_request_uri を返し、suite は来ないコールバックを待ち続けます。原因は署名アルゴリズムではありません。RS256 の OP に対する実行も同じ fetch で失敗します。
plan 別の内訳
バーは plan 1 件ごとに独立した尺度で、全幅がその plan 自身の module 数です。行の右端に分子と分母を出しているので、各区分は run 全体ではなくその plan に対する割合として読めます。plan の規模はバーの長さではなくこの数字で見てください。件数 0 の結果は行に出しません。
同じ snapshot を表で見る
| Plan | PASSED | REVIEW | SKIPPED | WARNING | FAILED | 未判定 | 合計 |
|---|---|---|---|---|---|---|---|
oidcc-basic-certification-test-plan | 30 | 3 | 2 | 0 | 0 | 0 | 35 |
oidcc-config-certification-test-plan | 1 | 0 | 0 | 0 | 0 | 0 | 1 |
oidcc-dynamic-certification-test-plan | 8 | 6 | 5 | 0 | 2 | 2 | 23 |
oidcc-formpost-basic-certification-test-plan | 30 | 3 | 2 | 0 | 0 | 0 | 35 |
oidcc-rp-initiated-logout-certification-test-plan | 3 | 8 | 0 | 0 | 0 | 0 | 11 |
oidcc-backchannel-rp-initiated-logout-certification-test-plan | 0 | 0 | 0 | 0 | 2 | 0 | 2 |
fapi2-security-profile-final-test-plan | 42 | 9 | 1 | 0 | 0 | 0 | 52 |
fapi2-message-signing-final-test-plan | 55 | 9 | 2 | 0 | 0 | 0 | 66 |
fapi-ciba-id1-test-plan | 32 | 0 | 2 | 0 | 0 | 0 | 34 |
| 合計 | 201 | 38 | 14 | 0 | 4 | 2 | 259 |
各テストプランが検証する範囲
OFCS の各テストプランは、それぞれ特定の仕様プロファイルを検証します。以下の表は、プランごとに「該当コードパスを有効化するライブラリオプション」と「その挙動を解説しているページ」を対応づけたものです。組み込み側は、自分の配備が同じ構成を公開しているかをこの表で確認できます。
oidcc-basic-certification-test-plan — OIDC Core 1.0
Basic プランは PKCE なしで code フローを実行するため、適合性検証用の OP は op.WithProfile(profile.OIDCCore) を宣言しています。OAuth 2.1 の既定ではこれらのリクエストを拒否します。
| 検証範囲 | 有効化に必要なオプション | 解説ページ |
|---|---|---|
| 認可コードフロー(confidential client では PKCE 任意) | op.WithProfile(profile.OIDCCore)。PKCE 自体は常にサポート | 認可コード + PKCE フロー |
| ID トークンの発行と claim | 既定で有効 | ID トークン / アクセストークン / userinfo |
| UserInfo エンドポイント | 既定で有効 | ID トークン / アクセストークン / userinfo |
Discovery (/.well-known/openid-configuration) | 既定で有効 | Discovery |
| JWKS の公開 | 既定で有効 | JWKS エンドポイント |
| リフレッシュトークン + ローテーション | 既定で有効、長期 refresh は offline_access スコープが必要 | リフレッシュトークン |
標準スコープ(profile、email、address、phone) | スコープごとに op.WithScope(...) を 1 回ずつ | scope と claim |
| public / pairwise サブジェクト | pairwise は op.WithPairwiseSubject(salt)、適用判定はクライアントの SubjectType | Pairwise subject |
fapi2-security-profile-final-test-plan — FAPI 2.0 Baseline
| 検証範囲 | 有効化に必要なオプション | 解説ページ |
|---|---|---|
| PAR (RFC 9126) | op.WithProfile(profile.FAPI2Baseline) がプロファイルとして feature.PAR を有効化 | FAPI 2.0 入門、FAPI 2.0 Baseline |
| JAR (RFC 9101) | プロファイルが feature.JAR を有効化 | FAPI 2.0 入門 |
S256 PKCE の強制 | プロファイルが強制 | 認可コード + PKCE フロー |
認可レスポンスの iss (RFC 9207) | プロファイルが強制 | Issuer |
ID トークン署名アルゴリズム ES256 | 既定。OP 発行 ID トークンは PS256 では署名せず、op.New は FAPI プロファイルと op.WithSigningAlgorithm(op.AlgRS256) の組み合わせを拒否する | JOSE 基礎 |
RS256(FAPI 文脈)・HS*・none の拒否 | FAPI プロファイルと RS256 の組み合わせは構築時エラー。HS* と none は internal/jose/alg.go の closed enum に存在しない | 設計判断 |
private_key_jwt | profile が強制。クライアントアサーションの aud は issuer を単一の文字列で指定する | クライアント種別 |
| DPoP または mTLS による送信者制約 | op.WithFeature(feature.DPoP) か op.WithFeature(feature.MTLS) のいずれか(FAPI 2.0 では少なくとも一方が必須) | 送信者制約の選定ガイド、DPoP、mTLS |
redirect_uri 完全一致 | プロファイルが強制 | Redirect URI |
| リフレッシュトークンをローテーションしない | profile.FAPI2Baseline と profile.FAPI2MessageSigning で profile が強制(FAPI 2.0 Security Profile Final §5.3.2.1)。それ以外の profile は既定でローテーションと再利用検知を行う | リフレッシュトークン |
fapi2-message-signing-final-test-plan — FAPI 2.0 Message Signing
Message Signing は Baseline に署名認可レスポンスを上乗せします。Baseline プランが検証する内容はこのプランでも全て実行され、プロファイル定数を切り替えるだけで JARM が自動有効化されます。
| 検証範囲 | 有効化に必要なオプション | 解説ページ |
|---|---|---|
| FAPI 2.0 Baseline の全項目(上記) | op.WithProfile(profile.FAPI2MessageSigning) | (上記と同じ) |
| 署名された認可レスポンス(JARM) | プロファイルが feature.JARM を有効化 | FAPI 2.0 入門(JARM セクション) |
| token レスポンスの ID トークン署名 | プロファイルが強制 | ID トークン / アクセストークン / userinfo |
request object 署名(PS256 / ES256) | プロファイルが強制 | FAPI 2.0 入門 |
fapi-ciba-id1-test-plan — FAPI-CIBA(Client-Initiated Backchannel Authentication)
CIBA プランは OpenID Connect Client-Initiated Backchannel Authentication grant を検証します。クライアントから開始された認証要求が、ユーザの認証デバイス(プッシュ通知、IVR 等)で非同期に完了し、ポーリング型の token 要求で消費される流れです。OP は poll mode で動作します。旧 FAPI-CIBA-ID1 プランは mTLS 証明書バインドのアクセストークンを使うため、デモは feature.MTLS を明示して tls_client_certificate_bound_access_tokens のメタデータに合わせています。ライブラリの一般的な profile.FAPICIBA 設定は DPoP も認め、どちらも指定しなければ DPoP を選ぶため、この設定だけでは ID1 プランを再現しません。
| 検証範囲 | 有効化に必要なオプション | 解説ページ |
|---|---|---|
/bc-authorize エンドポイント + auth_req_id | op.WithCIBAGrant(op.CIBAGrant{HintResolver: ...}) | CIBA ポーリング方式 |
ヒント解決(login_hint / id_token_hint / login_hint_token) | 組み込み側が HintResolver を提供 | CIBA ポーリング方式 |
ポーリング規律(authorization_pending / slow_down) | 既定で有効、CIBAGrant.PollInterval で advertised interval を上書き可 | CIBA ポーリング方式 |
| ポーリング濫用ロックアウトの上限 | 既定 5 strikes、CIBAGrant.MaxPollViolations で上下に調整可 | CIBA ポーリング方式 |
| 送信者制約付きアクセストークン | op.WithProfile(profile.FAPICIBA) は DPoP または mTLS を認め、指定がなければ DPoP を選ぶ。この OFCS デモは旧 ID1 プランに合わせて feature.MTLS を明示する | 送信者制約の選定ガイド、mTLS |
/bc-authorize への署名 request object | op.WithFeature(feature.JAR)(FAPI-CIBA で自動) | FAPI 2.0 入門 |
request_object の iat / exp claim 必須化(FAPI-CIBA §5.2.2) | プロファイルが強制 | FAPI 2.0 入門 |
REVIEW / SKIPPED / WARNING / FAILED の意味
- REVIEW — テストは実行されましたが、OP が描画したエラー画面や、ログイン画面が再表示されたかどうかなど、ハーネスからは見えない点を人間が確認する必要があります。スイートはスクリーンショットの提出段階で
WAITINGのまま待ち、OFCS の UI で誰かが「review 済み」にするまで進みません。ヘッドレス実行ではREVIEWをそのまま記録します。失敗ではありません。 - SKIPPED — テストが依存する機能を、この OP が discovery やクライアントメタデータで宣言していないため、スイートが実行しません。例えば
RS256負例テストは、スイートが FAPI プランに登録するクライアント JWKS にES256の鍵しかなく、負例に署名する RSA 鍵がないためスキップされます。失敗ではありません。 - WARNING — テストは終端の PASS に到達しましたが、advisory がログに残った状態です。現在の snapshot では 0 件 です。
- FAILED — module がスイートの期待する結果に到達しませんでした。この run の 4 件は、dynamic プランの 2 件(認可コードフロー専用のレスポンスタイプと、拒否される
userinfo_signed_response_algの登録)と、back-channel logout を意図的に subject 単位に留めていることによる 2 件です。いずれもレビュー済みの release exclusion で、明示的かつ期限内の記録がなければ release verifier は失敗します。 - 未判定 — ハーネスが module を終端結果まで駆動できなかった状態です。1 件は module の途中で署名鍵のローテーションを要求します。もう 1 件は、OP の
request_urifetcher が証明書を信頼しないホストに request object を公開するため、OP は redirect 前に拒否し、スイートは来ないコールバックを待ち続けます。どちらも、実稼働中の suite に対する単体実行の証跡付きで、レビュー済みの release exclusion に記録しています。
なぜ REVIEW を auto-pass しないか
スイートは意図的に、これらの module を人間の判断に委ねています。ヘッドレスで動く cmd/op-demo は「ユーザに見えた画面です」というスクリーンショットを誠実にアップロードできません。この関門を外して通すと、実際に確認した内容を偽ることになります。ハーネスは REVIEW のまま記録し、OpenID Foundation の認証を取る場合は UI で一件ずつ人が解消する前提です。
現在 FAILED の module — 理由
2 plan にまたがる 4 module です。各行は conformance/release-exclusions.json のレビュー済み・期限付きエントリと対応しており、記録が欠けている、担当者がいない、期限切れのいずれかであれば make conformance-release-verify がリリースを止めます。
| Module | Plan | 失敗する理由 |
|---|---|---|
oidcc-discovery-endpoint-verification | oidcc-dynamic | dynamic プロファイルは id_token と token id_token のレスポンスタイプと implicit grant も要求するが、本 OP はこれらを実装していない。失敗するのは response types と grant types の条件。 |
oidcc-userinfo-rs256 | oidcc-dynamic | UserInfo 暗号化なしで userinfo_signed_response_alg=RS256 を登録しようとするが、動的クライアント登録が invalid_client_metadata を返すため assertion まで到達しない。原因はアルゴリズムではない。 |
oidcc-backchannel-logout-discovery-endpoint-verification | oidcc-backchannel-rp-initiated-logout | 本 OP は仕様上許容される backchannel_logout_session_supported: false を広告するが、この module がそれを認めないため。 |
oidcc-backchannel-rp-initiated-logout | oidcc-backchannel-rp-initiated-logout | 上の module から連鎖。プランがその assertion で中断するため、この module は実行に到達しない。 |
現在未判定の module — 理由
ハーネスが終端結果まで駆動できなかった 2 module です。いずれも実稼働中の suite に対する単体実行で得た証跡付きで記録しています。
| Module | Plan | 判定が出ない理由 |
|---|---|---|
oidcc-server-rotate-keys | oidcc-dynamic | 運用者が署名鍵をローテーションして Start を押すのを待つ module です。鍵束は op.New で確定し、プラン実行中に provider を作り直すと登録済みクライアントを保持する in-memory store が失われます。module は runner の idle 上限まで CONFIGURED のまま留まります。 |
oidcc-request-uri-signed-rs256 | oidcc-dynamic | RS256 署名の request object を公開し、認可レスポンスの成功を待つ module です。OP は request_uri を取得できません。スイートは自己署名証明書で提供し、OP は conformance CA を JWKS fetcher にしか入れていないため、/authorize は redirect 前に invalid_request_uri を返し、スイートは来ないコールバックを待って WAITING のままになります。原因は署名アルゴリズムではありません。 |
現在 REVIEW の module
38 件はすべて、スイートが検証できるコールバックがない、または結果にかかわらず review 項目を記録するために、描画された画面を人間に見てほしいというケースです。OP が拒否または再プロンプトする場面では、拒否そのものをライブラリ側のテストで固定しています。
| Plan | Module | 人間の確認が要る理由 |
|---|---|---|
oidcc-basic、oidcc-formpost-basic(各 3 件) | oidcc-ensure-registered-redirect-uri | 未登録の redirect_uri へはリダイレクトしてはならないため、結果はエラーページになる。 |
oidcc-max-age-1、oidcc-prompt-login | セッションの再利用ではなく、ログイン画面が再び表示されたことを確認できるのは人間だけ。 | |
oidcc-dynamic(6 件) | oidcc-ensure-redirect-uri-in-authorization-request、oidcc-redirect-uri-query-added、oidcc-redirect-uri-query-mismatch | 1 行目と同じ。リダイレクトせずに拒否する。 |
oidcc-registration-logo-uri、oidcc-registration-policy-uri、oidcc-registration-tos-uri | 登録した URI が同意画面に出るかを人間に確認させる。表示されるかどうかは、組み込み側が用意する interaction driver で決まる。 | |
oidcc-rp-initiated-logout(8 件) | oidcc-rp-initiated-logout-* | どれも OP 自身が描画する画面(ログアウト確認、不正な id_token_hint や未登録の post_logout_redirect_uri のエラーページ)で終わる。拒否したログアウトは RP へ戻してはならないため。 |
fapi2-security-profile-final、fapi2-message-signing-final(各 9 件) | 下の 9 module | PAR request_uri の拒否、request object の不一致、PAR を使わない未署名リクエスト、request object の外側だけで渡された state は redirect 前に拒否され、確認用のエラーページが残る。long state / nonce の 2 module は例外で、OP は長い値を受け付けてフローは成功するが、module は結果にかかわらず review 項目を記録する。 |
FAPI 2.0 の 9 module です(2 つのプランに同じ名前が並ぶため、合計 18 件)。
fapi2-…-ensure-different-nonce-inside-and-outside-request-objectfapi2-…-ensure-different-state-inside-and-outside-request-objectfapi2-…-ensure-authorization-request-with-long-noncefapi2-…-ensure-authorization-request-with-long-statefapi2-…-ensure-unsigned-authorization-request-without-using-par-failsfapi2-…-par-attempt-reuse-request_urifapi2-…-par-attempt-to-use-expired-request_urifapi2-…-par-attempt-to-use-request_uri-for-different-clientfapi2-…-state-only-outside-request-object-not-used
現在 SKIPPED の module — 理由
14 件です。スキップは discovery とクライアント別メタデータの宣言から決まるため、ここに並ぶのは実行に失敗したテストではなく、意図して対応していない項目です。
| Module | Plan | 理由 |
|---|---|---|
fapi2-security-profile-final-ensure-signed-client-assertion-with-RS256-fails | fapi2-* の両プラン | これらの module は、RS256 署名のクライアントアサーションや request object が拒否されることを検証する。スイートが FAPI プランに登録するクライアント JWKS には ES256 の鍵しかなく、負例に署名する RSA 鍵がない。OP 側も FAPI プロファイルでは RS256 での発行を拒否する。 |
fapi2-security-profile-final-ensure-signed-request-object-with-RS256-fails | fapi2-message-signing-final | 同様。対象は request object。(Message Signing プランは security-profile の module 名を流用している。) |
fapi-ciba-id1-ensure-request-object-signature-algorithm-is-RS256-fails | fapi-ciba-id1 | 同様。対象は CIBA クライアントの request object。 |
fapi-ciba-id1-ensure-client-assertion-signature-algorithm-in-token-endpoint-request-is-RS256-fails | fapi-ciba-id1 | 同様。対象は token エンドポイントのクライアントアサーション。 |
oidcc-ensure-request-object-with-redirect-uri、oidcc-unsigned-request-object-supported-correctly-or-rejected-as-unsupported | oidcc-basic、oidcc-formpost-basic(両方)、oidcc-dynamic(前者のみ) | 非 FAPI プランの request object 系 module。discovery が宣言する request object の対応状況からスイートがスキップする。OP は alg=none を受け付けない。署名付き request object は、JAR が必須の FAPI プランで実行している。 |
oidcc-request-uri-unsigned | oidcc-dynamic | 同じ系統。request_uri の先が未署名の object である場合。 |
oidcc-idtoken-unsigned | oidcc-dynamic | 未署名の ID トークンを要求する。OP はすべての ID トークンに署名し、none を宣言していない。 |
oidcc-registration-sector-bad、oidcc-registration-sector-uri | oidcc-dynamic | sector_identifier_uri の module。pairwise サブジェクトは opt-in(op.WithPairwiseSubject)で、デモは dynamic プランを public サブジェクトで実行する。pairwise はライブラリ自身のテストと examples/34-pairwise-saas で検証している。 |
自分でベースラインを再現する
git clone https://github.com/libraz/go-oidc-provider.git
cd go-oidc-provider
make conformance-up
make conformance-baseline LABEL=local-check
ls conformance/baselines/ # JSON スナップショットがここに着地make conformance-up は、証明書の生成、https://localhost:8443 での OFCS コンテナ起動、https://127.0.0.1:9443 での cmd/op-demo のビルドと起動、OFCS REST API 経由の 9 plan の登録までを行います。続く make conformance-baseline が全 module を駆動し、module ごとの結果を決定論的な JSON に記録します。make conformance-baseline-diff は、2 つのスナップショット間で PASSED を 失った module があれば非ゼロで終了します。セキュリティ関連の変更をマージする前に、プロジェクトが使う回帰ゲートです。
各プランに必要な op.With... オプション、プランと起動フラグの対応表、リリースゲートは OFCS 再現レシピにあります。差分の取り方はベースラインの取得と差分を参照してください。
このコードベースでの FAPI 2.0 の意味
op.WithProfile(profile.FAPI2Baseline) は、2 つの fapi2-* プランが前提とする設定を有効にします。詳しい説明は FAPI 2.0 にあります。プランが検証する要素は次のとおりです。
feature.PARとfeature.JAR(どちらもFAPI2Baselineが自動で有効化):/oidc/parがルーティングされ、request/request_uriを署名付き JWT として検証します。feature.JARM(FAPI2MessageSigningがさらに自動で有効化): 認可レスポンスを署名付き JWT にします。- 送信者制約付きアクセストークン: プロファイルは DPoP か mTLS のどちらかを要求します。組み込み側が
feature.MTLS(cnf.x5t#S256)を有効にしていればそれで要件を満たし、DPoP の既定は追加されません。どちらも指定がなければop.Newがfeature.DPoP(cnf.jkt)を選ぶため、素のop.WithProfile(profile.FAPI2Baseline)でも送信者制約付きで起動します。DPoP が有効なら、discovery はdpop_signing_alg_values_supported: ES256, EdDSA, PS256を宣言します。 - クライアントアサーションの
audは issuer を単一の文字列で指定したものだけを受け付け、refresh token はローテーションしません(profile.FAPI2Baselineとprofile.FAPI2MessageSigning)。 - JOSE の alg 許可リストはコードベース全体で
RS256 / PS256 / ES256 / EdDSAに固定され、HS*とnoneは構造的に到達できません(internal/jose/alg.goを参照)。 token_endpoint_auth_methods_supportedは FAPI の本番経路(private_key_jwt)に絞られ、redirect_uriは完全一致で判定します。- クライアントごとの
RequestObjectSigningAlg/TokenEndpointAuthSigningAlgで各 FAPI クライアントをPS256(またはES256/EdDSA)に絞ります。discovery にはコードベース全体のリストを載せたままです。
WithProfile のあとにプロファイルと衝突するオプションを設定すると、op.New(...) は構築時にエラーを返します。FAPI として中途半端な設定が本番に出ることはありません。
ハーネスの構成ファイル
| Path | 内容 |
|---|---|
conformance/README.md | 運用 runbook |
conformance/plans/*.json | プランテンプレート(server / client / resource ブロック) |
conformance/docker-compose.yml | 現在の OFCS イメージ pin(release-v5.3.4)と JKS truststore の設定 |
conformance/release-exclusions.json | リリースゲートが受け入れる、レビュー済み・期限付きの例外 |
scripts/conformance.sh | certs / ofcs-up / op-up / seed-plans / drive / batch / baseline / baseline-diff / release-verify |
tools/conformance/ | REST クライアント、ヘッドレス実行スクリプト、baseline と release-verify のロジック(Python) |
conformance/baselines/*.json | 取得済みスナップショット(gitignored — 環境依存) |
明示しておく制限事項
- プランスイートのバージョン。 本ページの run は OFCS
release-v5.3.4で実行しており、これはdocker-compose.ymlの現在の既定 pin でもあります。 - ヘッドレス実行。 実行スクリプトは OFCS の REST API をリバースエンジニアリングしたもので、OFCS 側にドキュメントはありません。
- 本物の RP 証明書なし。 mTLS プラン枠は
conformance/certs/の生成済み自己署名証明書を使っており、プランをインスタンス化できる程度に整えてあるだけです。本物の CA チェーン検証はしていません。 - OP インスタンス 1 個。 インスタンス間の挙動(例: ストアを共有する 2 つの OP をまたぐトークン introspection)は OFCS ではなく
test/scenariosで検査します。
conformance ハーネスは test/scenarios/ 配下の in-process Spec Scenario Suite と並走します。OFCS はライブの OP に HTTP 経由で end-to-end に実行し、scenario suite は同じプロトコル不変条件を in-process で実行します。セキュリティ関連の変更は、両方が通ってからマージします。