OFCS 適合状況
go-oidc-provider は OpenID Foundation Conformance Suite (OFCS) に対して回帰検査されています。ハーネスはソースリポジトリの conformance/ に置かれており、9 つの OFCS plan を scaffold します。本ページの baseline は、そのうち現在の 4 plan security snapshot を cmd/op-demo インスタンスに対して end-to-end で実行した結果です。
個人開発、認証取得は無し
これは個人開発者が維持するプロジェクトです。OpenID Foundation 会員費は支払っておらず、形式的な OIDC 認証は取得していません。本ページの数値は、下に示す plan set の再現可能なスナップショットです。これは有償の OpenID Foundation 認証の代替ではなく、そのように引用しないでください。
この snapshot が検査する範囲
| Plan | カバー範囲 | プロファイル |
|---|---|---|
oidcc-basic-certification-test-plan | 認可コード + PKCE、ID トークン、UserInfo、refresh、discovery | OIDC Core 1.0 |
fapi2-security-profile-id2-test-plan | + PAR、送信者制約付きアクセストークン (DPoP)、厳格 alg list、redirect_uri 完全一致 | FAPI 2.0 Baseline |
fapi2-message-signing-id1-test-plan | + JAR(署名 authorization request)、JARM(署名 authorization response) | FAPI 2.0 Message Signing |
fapi-ciba-id1-test-plan | Client-Initiated Backchannel Authentication(poll mode)、mTLS バインドトークン | FAPI-CIBA |
最新 baseline
取得日時: 2026-06-14T07:18:03Z
リリースラベル: v0.9.3
リポジトリ SHA: ae2def2
OFCS イメージ: release-v5.1.42
| Plan | PASSED | REVIEW | SKIPPED | WARNING | FAILED | 合計 |
|---|---|---|---|---|---|---|
oidcc-basic-certification-test-plan | 30 | 3 | 2 | 0 | 0 | 35 |
fapi2-security-profile-id2-test-plan | 48 | 9 | 1 | 0 | 0 | 58 |
fapi2-message-signing-id1-test-plan | 60 | 9 | 2 | 0 | 0 | 71 |
fapi-ciba-id1-test-plan | 32 | 0 | 3 | 0 | 0 | 35 |
| 合計 | 170 | 21 | 8 | 0 | 0 | 199 |
各テストプランが検証する範囲
OFCS の各テストプランは、それぞれ特定の仕様プロファイルを検証します。以下の表は、プランごとに「該当コードパスを有効化するライブラリオプション」と「その挙動を解説しているページ」を対応づけたものです。組み込み側は、自分の deployment が同じ構成を露出しているかをこの表で確認できます。
oidcc-basic-certification-test-plan — OIDC Core 1.0
| 検証範囲 | 有効化に必要なオプション | 解説ページ |
|---|---|---|
| 認可コードフロー + PKCE | 既定で有効 | /ja/concepts/authorization-code-pkce |
| ID トークンの発行と claim | 既定で有効 | /ja/concepts/tokens |
| UserInfo エンドポイント | 既定で有効 | /ja/concepts/tokens |
Discovery (/.well-known/openid-configuration) | 既定で有効 | /ja/concepts/discovery |
| JWKS の公開 | 既定で有効 | /ja/operations/jwks |
| リフレッシュトークン + ローテーション | 既定で有効、長期 refresh は offline_access スコープが必要 | /ja/concepts/refresh-tokens |
標準スコープ (profile、email、address、phone) | スコープごとに op.WithScope(...) を 1 回ずつ | /ja/concepts/scopes-and-claims |
| public / pairwise サブジェクト | pairwise は op.WithPairwiseSubject(salt)、適用判定はクライアントの SubjectType | /ja/use-cases/pairwise-subject |
fapi2-security-profile-id2-test-plan — FAPI 2.0 Baseline
| 検証範囲 | 有効化に必要なオプション | 解説ページ |
|---|---|---|
| PAR (RFC 9126) | op.WithProfile(profile.FAPI2Baseline) がプロファイルとして feature.PAR を有効化 | /ja/concepts/fapi、/ja/use-cases/fapi2-baseline |
| JAR (RFC 9101) | プロファイルが feature.JAR を有効化 | /ja/concepts/fapi |
S256 PKCE の強制 | プロファイルが強制 | /ja/concepts/authorization-code-pkce |
認可レスポンスの iss (RFC 9207) | プロファイルが強制 | /ja/concepts/issuer |
ID トークン署名アルゴリズム ES256 | プロファイルが強制。OP 発行 ID トークンは PS256 / RS256 では署名しない | /ja/concepts/jose-basics |
RS256(FAPI 文脈)・HS*・none の拒否 | internal/jose/alg.go の closed enum で禁止 | /ja/security/design-judgments |
private_key_jwt または tls_client_auth | プロファイルが強制(FAPI allow-list と交差) | /ja/concepts/client-types |
| DPoP または mTLS による送信者制約 | op.WithFeature(feature.DPoP) か op.WithFeature(feature.MTLS) のいずれか(FAPI 2.0 では少なくとも一方が必須) | /ja/concepts/sender-constraint、/ja/concepts/dpop、/ja/concepts/mtls |
redirect_uri 完全一致 | プロファイルが強制 | /ja/concepts/redirect-uri |
| リフレッシュトークンのローテーションと再利用検知 | 既定で有効 | /ja/concepts/refresh-tokens |
fapi2-message-signing-id1-test-plan — FAPI 2.0 Message Signing
Message Signing は Baseline に署名認可レスポンスを上乗せします。Baseline プランが検証する内容はこのプランでも全て実行され、プロファイル定数を切り替えるだけで JARM が自動有効化されます。
| 検証範囲 | 有効化に必要なオプション | 解説ページ |
|---|---|---|
| FAPI 2.0 Baseline の全項目(上記) | op.WithProfile(profile.FAPI2MessageSigning) | (上記と同じ) |
| 署名された認可レスポンス(JARM) | プロファイルが feature.JARM を有効化 | /ja/concepts/fapi(JARM セクション) |
| token レスポンスの ID トークン署名 | プロファイルが強制 | /ja/concepts/tokens |
request object 署名 (PS256 / ES256) | プロファイルが強制 | /ja/concepts/fapi |
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 は FAPI 1.0 のハードコード要件を引き継ぎ tls_client_certificate_bound_access_tokens を必須にするため、mTLS 送信者制約が必須です。
| 検証範囲 | 有効化に必要なオプション | 解説ページ |
|---|---|---|
/bc-authorize エンドポイント + auth_req_id | op.WithCIBA(op.WithCIBAHintResolver(...)) | /ja/use-cases/ciba |
ヒント解決(login_hint / id_token_hint / login_hint_token) | 組み込み側が HintResolver を提供 | /ja/use-cases/ciba |
ポーリング規律(authorization_pending / slow_down) | 既定で有効、op.WithCIBAPollInterval(...) で advertised interval を上書き可 | /ja/use-cases/ciba |
| ポーリング濫用ロックアウトの上限 | 既定 5 strikes、op.WithCIBAMaxPollViolations(n) で上下に調整可 | /ja/use-cases/ciba |
tls_client_certificate_bound_access_tokens(FAPI-CIBA 必須) | op.WithProfile(profile.FAPICIBA) が feature.MTLS を有効化 | /ja/concepts/mtls |
/bc-authorize への署名 request object | op.WithFeature(feature.JAR)(FAPI-CIBA で自動) | /ja/concepts/fapi |
request_object の iat / exp クレーム必須化(FAPI-CIBA §5.2.2) | プロファイルが強制 | /ja/concepts/fapi |
REVIEW / SKIPPED / WARNING / FAILED の意味
- REVIEW — テストは実行されたが、ハーネスでは正直に検証できない視覚的 / out-of-band の挙動(同意 UI の文言、エラー画面のスクリーンショット、証明書チェーンの確認)を人間のレビュアーが裏取りする必要がある状態。失敗ではない。
- SKIPPED — テストが依存する機能を、この OP が discovery やクライアントメタデータで宣言していないために OFCS が実行を見送った状態。例えば
RS256負例テストは、FAPI クライアントがPS256を署名 alg として宣言しているため適用外になる。失敗ではない。 - WARNING — OFCS が非 failure の result value として記録する状態。主たる assertion は終端 PASS まで到達したが、運用者が対処すべき advisory がログに残っている場合に使われます。現在の 4 plan snapshot では 0 件 です。
- FAILED — 仕様から挙動が逸脱した状態。現スナップショットでは 4 plan 全体で 0 failure。
自分で conformance を回すには
- 該当プロファイルを組み込んだ OP を立ち上げます — security プロファイルなら
op.WithProfile(profile.FAPI2Baseline)、message signing ならop.WithProfile(profile.FAPI2MessageSigning)、FAPI-CIBA ならop.WithProfile(profile.FAPICIBA)と CIBA オプション、OIDC Core プランならWithProfile無し。 - プランを OFCS deployment に登録します。conformance suite は OpenID Foundation が運用しています。ソースリポジトリの
conformance/配下にプランテンプレートとローカル起動用の固定 Docker イメージが入っています。 - プランを実行します。ハーネスは
/authorize、/par、/token、/userinfo、/jwksほか discovery で公開された各エンドポイントを必須経路で全て呼び出し、JSON スナップショットを書き出します。記録済 baseline との差分が取れます。
詳細な runbook(make ターゲット、JSON スナップショットの構造、差分ゲート)は下の自分でベースラインを再現するを参照してください。
REVIEW と FAILED の違い
OFCS は主に PASSED、FAILED、REVIEW、SKIPPED を返します。本ハーネスは OFCS が advisory として出す WARNING result もそのまま保持します。REVIEW はテスト失敗を意味しません。 自動化では確認できない箇所を人間の運用者に確認してほしい、という意味です — 例「OP はここでログイン画面を表示したか?」。テストは実行され、スクリーンショットを撮り、誰かが OFCS UI で「review 済み」をクリックするまで WAITING に留まります。本ハーネスはそこに到達してエラーが出なければ REVIEW を記録します。
なぜ REVIEW を auto-pass しないか
conformance suite は意図的にこれらの module を人間の判断にゲートしています。ヘッドレスで動く cmd/op-demo は「これがユーザに見えた画面です」というスクリーンショットを誠実にアップロードできません。ゲートを外して通してしまうのは、実際にチェックされた内容を偽ることになります。ハーネスは REVIEW のまま記録し、有償認証取得時は UI を見ながら通すことを前提にしています。
現在 REVIEW の module
oidcc-basic plan (3)
| Module | ゲート対象 |
|---|---|
oidcc-ensure-registered-redirect-uri | OP が未登録 redirect_uri を拒否したことの手動確認 |
oidcc-max-age-1 | max_age=1 でユーザを再プロンプトしたことの手動確認 |
oidcc-prompt-login | prompt=login で再プロンプトしたことの手動確認 |
FAPI 2.0 plans (各 9、同集合)
これらは全て、OP のエラーページのスクリーンショット upload か「ユーザが実際に再プロンプトされたか」の手動判断にゲートされます。ヘッドレスでも問題なく実行できますが、人間のサインオフが入るまでは REVIEW に留まります(fapi2-security-profile-id2 と fapi2-message-signing-id1 の両プランで同じ 9 件が REVIEW になり、合計 18 件です):
fapi2-…-ensure-different-nonce-inside-and-outside-request-objectfapi2-…-ensure-different-state-inside-and-outside-request-objectfapi2-…-ensure-request-object-with-long-noncefapi2-…-ensure-request-object-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
OP は各ケースで正しい HTTP エラーを返します(負例テストの内部 assertion は通過)— OFCS が描画されたエラー UI を人間に inspect してもらいたいだけです。
現在 WARNING の module
現在の 4 plan snapshot ではありません。以前 WARNING だった fapi-ciba-id1-refresh-token は、通常の PASSED module になっています。
現在 SKIPPED の module — 理由
| Module | 理由 |
|---|---|
fapi2-…-ensure-signed-client-assertion-with-RS256-fails(×2) | プランで使う FAPI クライアントが token_endpoint_auth_signing_alg=PS256 を登録しているため、OFCS はクライアント別 RS256 負例を fapi2 系両プランでスキップ。 |
fapi2-message-signing-…-ensure-signed-request-object-with-RS256-fails | 同様 — FAPI クライアントの request_object_signing_alg=PS256 が RS256 負例を該当外にする。 |
fapi-ciba-id1-ensure-request-object-signature-algorithm-is-RS256-fails | FAPI-CIBA クライアントが request_object_signing_alg=PS256 を登録しているためスキップ。 |
fapi-ciba-id1-ensure-client-assertion-signature-algorithm-in-backchannel-authorization-request-is-RS256-fails | 同様 — CIBA クライアントの token_endpoint_auth_signing_alg=PS256。 |
fapi-ciba-id1-ensure-client-assertion-signature-algorithm-in-token-endpoint-request-is-RS256-fails | 同様。 |
oidcc-ensure-request-object-with-redirect-uri | oidcc-basic プランは JAR を有効化しないため、OP は discovery から request_object_signing_alg_values_supported を省略し OFCS はスキップ。 |
oidcc-unsigned-request-object-supported-correctly-or-rejected-as-unsupported | 同様 — JAR off、request パラメータ無し、OFCS スキップ。 |
"SKIPPED" は意図的、「走らなかった」ではない
OFCS のスキップ判定は、discovery とクライアント別メタデータが宣伝する内容に基づきます。プラン内の FAPI クライアントは PS256 をトークンエンドポイント認証 / request object 署名 alg として宣言しているため、OFCS の「RS256 は失敗すべき」プローブは適用外と判定され、「実際に実行して pass を記録する」のではなく skipped になります。
自分でベースラインを再現する
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 スナップショットがここに着地ハーネスは:
- 自己署名 RSA-2048 証明書を生成(
scripts/conformance.sh certs)。 https://localhost:8443で OFCS Docker スタックを立ち上げ。https://127.0.0.1:9443でcmd/op-demoをビルド・起動。- OFCS REST API 経由で plan を seed。ハーネスは 9 plan を scaffold し、上の最新 status table は 4 plan security snapshot を記録しています。
- module 毎の pass/fail を決定論的 JSON に記録。
make conformance-baseline-diff は 2 スナップショット間で PASSED を 失った module があれば非ゼロ終了 — セキュリティ関連変更に対するプロジェクトのプリマージゲートです。
このコードベースでの FAPI 2.0 の意味
op.WithProfile(profile.FAPI2Baseline) は 2 つの fapi2-* plan が想定する設定を有効化します:
feature.PAR(FAPI2Baselineで自動有効化) —/parがルート可能、/authorizeでrequest_uriを受理feature.JAR(FAPI2Baselineで自動有効化) —request/request_uriを署名 JWT として検証feature.JARM(FAPI2MessageSigningで追加で自動有効化) — 認可レスポンスを JWT として署名- 送信者制約付きアクセストークン — プロファイルは DPoP-or-mTLS 要件を課します。組み込み側が
feature.MTLS(cnf.x5t#S256)を明示的に有効化した場合はそれで要件を満たし、DPoP 既定は追加されません。どちらも明示されていない場合、op.Newはfeature.DPoP(cnf.jkt)を標準の既定として選ぶため、素のop.WithProfile(profile.FAPI2Baseline)でも sender-constrained access token 付きで起動します。DPoP が有効なら discovery はdpop_signing_alg_values_supported: ES256, EdDSA, PS256を宣伝 - JOSE alg allow-list はコードベース全体で
RS256 / PS256 / ES256 / EdDSAにロック、HS*とnoneは 構造的 に到達不能(internal/jose/alg.go参照) token_endpoint_auth_methods_supportedを FAPI allow-list(private_key_jwt、tls_client_auth、self_signed_tls_client_auth)と交差redirect_uri完全一致を強制- クライアント別
RequestObjectSigningAlg/TokenEndpointAuthSigningAlgで各 FAPI クライアントをPS256(またはES256/EdDSA)に絞り込みつつ、discovery doc にはコードベース全体のリストを掲載
WithProfile 後にプロファイルと衝突するオプションを設定すると、op.New(...) は本番に partial-FAPI を出さず構築時エラーを返します。
ハーネスの構成ファイル
| Path | 内容 |
|---|---|
conformance/README.md | 運用 runbook |
conformance/plans/*.json | プランテンプレート(server / client / resource ブロック) |
conformance/docker-compose.yml | OFCS イメージのタグ固定(release-v5.1.42)+ JKS truststore 実装 |
scripts/conformance.sh | certs / ofcs-up / op-up / seed-plans / drive / batch |
tools/conformance/ofcs.py | REST クライアント + ヘッドレス drive スクリプト |
conformance/baselines/*.json | 取得済スナップショット(gitignored — 環境依存) |
明示しておく制限事項
- プランスイートのバージョン。 OFCS は
release-v5.1.42で固定しています。新しい OFCS リリースで追加・改名されたテストは、固定バージョンを引き上げるまで対象外です。 - ヘッドレス実行。 実行スクリプトは OFCS の REST API をリバースエンジニアリングしているもので、OFCS 側にドキュメントはありません。挙動確認は v5.1.42 でしか取れていません。
- 本物の RP 証明書なし。 mTLS プラン枠は
conformance/certs/の生成済み自己署名証明書を使っており、プランをインスタンス化できる程度に整えてあるだけです。本物の CA チェーン検証はしていません。 - OP インスタンス 1 個。 インスタンス間挙動(例: ストア共有の OP 2 個でのトークン introspection)は OFCS ではなく
test/scenariosで検査します。
conformance ハーネスは test/scenarios/ 配下の in-process Spec Scenario Suite と並走します。前者はライブ OP に対して HTTP 経由で end-to-end に実行し、後者は同じプロトコル不変条件を in-process で実行します — 両方が緑であることをセキュリティ関連変更の前提にしています。