Agent skill
fapi
FAPI(Financial-grade API)機能の開発・修正を行う際に使用。FAPI 1.0 Baseline/Advanced, FAPI CIBA, mTLS, PAR, JARM実装時に役立つ。
Install this agent skill to your Project
npx add-skill https://github.com/majiayu000/claude-skill-registry/tree/main/skills/other/other/fapi
SKILL.md
FAPI(Financial-grade API)開発ガイド
ドキュメント
documentation/docs/content_06_developer-guide/04-implementation-guides/oauth-oidc/fapi.md- FAPI実装ガイドdocumentation/docs/content_03_concepts/03-authentication-authorization/concept-06-fapi.md- FAPI概念documentation/docs/content_10_ai_developer/ai-32-extension-fapi.md- AI開発者向けFAPIガイドdocumentation/docs/content_06_developer-guide/03-application-plane/02-01-authorization-request-verification.md- 認可リクエスト検証フロー詳細(プロファイル決定、検証チェーン、エラーハンドリング)documentation/requirements/fapi-1.0-gap-analysis.yaml- FAPI 1.0 Gap分析(OIDF適合性テスト結果と修正記録)documentation/docs/content_05_how-to/phase-2-security/05-fapi-setup.md- FAPIセットアップガイド(プロファイル決定、認可サーバー/クライアント設定、OIDF認定チェックリスト)documentation/requirements/fapi-1.0-advanced-op-test-mapping.md- FAPI 1.0 Advanced OPテスト63件とRFC/仕様要件のマッピング表
機能概要
FAPIは、金融グレードのセキュリティを実現するOIDC/OAuth 2.0プロファイル。
- FAPI 1.0 Baseline Profile: 基本的なセキュリティ要件
- FAPI 1.0 Advanced Profile: 高度なセキュリティ要件(PAR, JARM, mTLS必須)
- FAPI CIBA Profile: CIBAとFAPIの組み合わせ
- Sender-constrained Access Token: mTLSバインディング
プロファイル適用条件
FAPIプロファイルはリクエストのスコープとテナントのextension設定で自動決定される。
| 優先度 | 条件 | プロファイル |
|---|---|---|
| 1 | テナントextension.fapi_advance_scopesに該当するスコープあり |
FAPI_ADVANCE |
| 2 | テナントextension.fapi_baseline_scopesに該当するスコープあり |
FAPI_BASELINE |
| 3 | openidスコープを含む |
OIDC |
| 4 | 上記以外 | OAUTH2 |
CIBAフローではbaseline/advanceどちらのスコープでも FAPI_CIBA になる。
詳細: content_06_developer-guide/03-application-plane/02-01-authorization-request-verification.md セクション2.3〜3(プロファイル決定、検証チェーン、エラーハンドリング)
モジュール構成
libs/
├── idp-server-core-extension-fapi/ # FAPI拡張モジュール
│ └── .../extension/fapi/
│ ├── FapiBaselineVerifier.java # FAPI Baseline検証
│ ├── FapiAdvanceVerifier.java # FAPI Advanced検証
│ ├── FapiProfileValidator.java # FAPIプロファイル検証
│ ├── TlsClientAuthAuthenticator.java # mTLSクライアント認証
│ └── SelfSignedTlsClientAuthAuthenticator.java
│
├── idp-server-core-extension-fapi-ciba/ # FAPI-CIBA拡張
│ └── .../extension/fapi/ciba/
│ └── FapiCibaVerifier.java
│
├── idp-server-core/ # コア(PAR, JARM実装)
│ └── .../oauth/
│ ├── request/
│ │ └── OAuthPushedRequestParameters.java # PAR
│ ├── response/
│ │ └── JarmCreatable.java # JARM
│ ├── io/
│ │ ├── OAuthPushedRequest.java
│ │ └── OAuthPushedRequestResponse.java
│ └── verifier/extension/
│ └── JarmVerifier.java
│
└── idp-server-control-plane/ # 管理API
└── .../management/fapi/
└── FapiConfigManagementApi.java
FAPI Baseline検証
idp-server-core-extension-fapi/ モジュール内:
public class FapiBaselineVerifier {
public void verify(
AuthorizationRequest request,
Client client
) {
// 1. response_type=code only
if (!request.responseType().isCode()) {
throw new InvalidRequestException(
"fapi_baseline_requires_code_flow"
);
}
// 2. PKCE必須(S256のみ)
if (!request.hasCodeChallenge()) {
throw new InvalidRequestException(
"code_challenge_required"
);
}
if (request.codeChallengeMethod() != CodeChallengeMethod.S256) {
throw new InvalidRequestException(
"code_challenge_method_must_be_s256"
);
}
// 3. state必須
if (!request.hasState()) {
throw new InvalidRequestException("state_required");
}
// 4. nonce必須(OpenID Connect時)
if (request.scope().contains("openid") &&
!request.hasNonce()) {
throw new InvalidRequestException("nonce_required");
}
}
}
FAPI Advanced検証
public class FapiAdvanceVerifier {
public void verify(
AuthorizationRequest request,
Client client
) {
// Baseline要件チェック
fapiBaselineVerifier.verify(request, client);
// 1. PAR必須
if (!request.isPushedAuthorizationRequest()) {
throw new InvalidRequestException(
"par_required_for_fapi_advanced"
);
}
// 2. JARM必須
if (!request.hasResponseMode() ||
!request.responseMode().isJwt()) {
throw new InvalidRequestException(
"jarm_required_for_fapi_advanced"
);
}
// 3. mTLS必須
if (!request.hasMtlsCertificate()) {
throw new InvalidRequestException(
"mtls_required_for_fapi_advanced"
);
}
}
}
PAR(Pushed Authorization Requests)
idp-server-core/oauth/request/ および oauth/io/ 内:
PAR実装は以下のクラスで構成:
OAuthPushedRequestParameters- PAR処理OAuthPushedRequest- リクエスト表現OAuthPushedRequestResponse- レスポンス表現
PARレスポンスのHTTPステータスコード
RFC 9126 Section 2.2 に従い、PAR成功レスポンスは HTTP 201 Created を返す。
OAuthPushedRequestStatus.CREATED(201)- 成功ステータスOAuthV1ApiのPARエンドポイントはresponse.statusCode()でステータスを動的に決定
PAR + FAPI Advanced の検証アーキテクチャ
FAPI Advanced では認可リクエストに JWS 署名付き Request Object が必須(Section 5.2.2 clause 1)。 PAR 経由のリクエストでは、以下の2段階で検証が分離される:
1. PARエンドポイント(OAuthRequestHandler.handlePushedRequest)
- クライアントは plain パラメータ または Request Object(JWT)を PAR エンドポイントに POST
OAuthRequestPatternがNORMALまたはREQUEST_OBJECTとして解析されるOAuthRequestVerifier.verify()で FAPI Advanced の全検証を実行(署名、exp、nbf、aud 含む)- 検証通過後、
AuthorizationRequestをリポジトリに保存 request_uri(urn:ietf:params:oauth:request_uri:...)を発行
2. 認可エンドポイント(OAuthRequestHandler.handleRequest)
- クライアントは
client_id+request_uriで認可エンドポイントにアクセス OAuthRequestPatternがPUSHED_REQUEST_URIとして解析されるPushedRequestUriPatternContextCreatorが保存済みパラメータを復元- JoseContext は空(保存時に JoseContext 情報は保持されない)
FapiAdvanceVerifierは PAR 経由の場合、以下の検証をスキップ:- Request Object 署名検証(
isUnsignedRequestObject) - JWT クレーム検証(exp、nbf、aud)
- Request Object 署名検証(
- 以下の検証は PAR 経由でも実行:
- JARM 設定チェック
- response_type / response_mode 検証
- sender-constrained access token 検証
- クライアント認証方式検証
- public client 拒否
PARエンドポイント 認可エンドポイント
┌─────────────────────┐ ┌─────────────────────┐
│ パラメータ受信 │ │ request_uri 受信 │
│ ↓ │ │ ↓ │
│ パターン解析 │ │ PUSHED_REQUEST_URI │
│ (NORMAL/REQUEST_OBJ) │ │ ↓ │
│ ↓ │ │ 保存済みパラメータ復元 │
│ FAPI Advanced 全検証 │ │ (JoseContext は空) │
│ (署名,exp,nbf,aud) │ │ ↓ │
│ ↓ │ │ FAPI Advanced 検証 │
│ クライアント認証 │ │ (JWT検証はスキップ) │
│ ↓ │ │ ↓ │
│ AuthzRequest 保存 │ │ 認可処理続行 │
│ ↓ │ └─────────────────────┘
│ request_uri 発行 │
└─────────────────────┘
関連ファイル:
FapiAdvanceVerifier.java- PAR判定とスキップロジックOAuthRequestHandler.java- PAR/認可の2段階ハンドリングPushedRequestUriPatternContextCreator.java- PAR復元時の空JoseContext生成OAuthRequestPattern.java- NORMAL / REQUEST_OBJECT / REQUEST_URI / PUSHED_REQUEST_URI の4パターンOAuthPushedRequestStatus.java- CREATED(201) / BAD_REQUEST(400) / UNAUTHORIZED(401) / SERVER_ERROR(500)
JARM(JWT-secured Authorization Response Mode)
idp-server-core/oauth/response/ 内:
JARM実装は以下のクラスで構成:
JarmCreatable- JARM生成インターフェースJarmVerifier- JARM検証
mTLS(Mutual TLS)
idp-server-core-extension-fapi/ 内:
mTLS実装は以下のクラスで構成:
TlsClientAuthAuthenticator- tls_client_auth方式SelfSignedTlsClientAuthAuthenticator- self_signed_tls_client_auth方式
E2Eテスト
e2e/src/tests/
├── spec/
│ ├── fapi_baseline.test.js # FAPI Baseline仕様
│ ├── fapi_advance.test.js # FAPI Advanced仕様
│ ├── fapi_ciba.test.js # FAPI CIBA仕様
│ ├── rfc9126_par.test.js # PAR (RFC 9126)
│ └── jarm.test.js # JARM仕様
│
├── usecase/financial-grade/
│ ├── financial-grade-01-transfer-flow.test.js
│ └── financial-grade-02-authentication-device-rule.test.js
│
└── security/
└── (FAPI関連セキュリティテスト)
コマンド
# ビルド
./gradlew :libs:idp-server-core-extension-fapi:compileJava
./gradlew :libs:idp-server-core-extension-fapi-ciba:compileJava
# テスト
cd e2e && npm test -- spec/fapi_baseline.test.js
cd e2e && npm test -- spec/fapi_advance.test.js
cd e2e && npm test -- spec/rfc9126_par.test.js
cd e2e && npm test -- usecase/financial-grade/
OIDF適合性テスト(OIDF Conformance Test Suite)
概要
OpenID Foundation (OIDF) が提供する適合性テストスイートで、FAPI仕様への準拠を自動検証する。
テストスイートURL: https://www.certification.openid.net/
本プロジェクトでは以下の2つのテストプランを実行:
| テストプラン | 内容 | テスト数 |
|---|---|---|
FAPI 1.0 Advanced Final (fapi1-advanced-final-test-plan) |
認可フロー、Request Object検証、JARM、mTLS、エラーハンドリング | ~30テスト |
FAPI-CIBA ID1 (fapi-ciba-id1-test-plan) |
CIBAフロー、poll/pingモード、Request Object検証、Refresh Token | ~30テスト |
テスト環境の構成
OIDF Conformance Suite (https://www.certification.openid.net/)
↕ HTTPS
ローカル idp-server (api.local.dev / mtls.api.local.dev)
↕
Financial-grade テナント (tenant_id: c3d4e5f6-a7b8-c9d0-e1f2-a3b4c5d6e7f8)
OIDFテストスイートがローカルサーバーにHTTPSでアクセスするため、ローカル環境が外部からアクセス可能である必要がある(ngrok等のトンネリングまたはDNS設定)。
financial-gradeテナントのセットアップ
# 1. ローカル環境起動
docker compose up -d
# 2. financial-gradeテナント作成(管理APIで組織・テナント・クライアント一括作成)
cd config/examples/financial-grade
./setup.sh
# 3. テナント設定の更新(既存テナントの設定変更時)
./update.sh
# 4. テナント削除(クリーンアップ)
./delete.sh
setup.sh が行うこと:
.envから管理者認証情報を読み込み、アクセストークンを取得onboarding-request.jsonを使って組織+テナント+クライアント群を一括作成- 認証ポリシー、認証設定(FIDO2等)を個別APIで設定
- テストユーザーを作成
主要設定ファイル:
| ファイル | 内容 |
|---|---|
onboarding-request.json |
テナント定義 + 全クライアント定義(一括オンボーディング) |
financial-tenant.json |
テナント設定のリファレンス(discovery応答に反映される値) |
tls-client-auth-client.json |
tls_client_auth方式クライアント |
tls-client-auth-client-2.json |
tls_client_auth方式クライアント(2nd client for OIDF) |
private-key-jwt-client.json |
private_key_jwt方式クライアント |
financial-client.json |
self_signed_tls_client_auth方式クライアント |
authentication-policy/oauth.json |
FAPI用認証ポリシー |
certs/ |
mTLSクライアント証明書・CA証明書 |
OIDF テスト設定ファイル
OIDFテストスイートにインポートするJSON設定:
config/examples/financial-grade/oidc-test/
├── fapi/
│ └── tls_client_auth.json # FAPI 1.0 Advanced Final (tls_client_auth)
└── fapi-ciba/
├── tls_client_auth_poll.json # FAPI-CIBA (tls_client_auth + poll)
├── private_key_jwt_poll.json # FAPI-CIBA (private_key_jwt + poll)
└── FAPI-CIBA-test-cases.md # テストケース詳細ドキュメント
設定ファイルの構造:
{
"alias": "テスト計画の識別名",
"server": {
"discoveryUrl": "https://api.local.dev/{tenant_id}/.well-known/openid-configuration"
},
"client": { "client_id": "...", "scope": "...", "jwks": {...} },
"client2": { "client_id": "...", "scope": "...", "jwks": {...} },
"mtls": { "key": "...", "cert": "..." },
"mtls2": { "key": "...", "cert": "..." },
"resource": {
"resourceUrl": "https://mtls.api.local.dev/{tenant_id}/v1/me/identity-verification/applications"
}
}
注意:
discoveryUrlは通常エンドポイント (api.local.dev)resourceUrlはmTLSエンドポイント (mtls.api.local.dev) — sender-constrainedトークン検証にクライアント証明書が必要clientとclient2は2クライアントテスト用(証明書バインドアクセストークンの交差検証等)mtls/mtls2はそれぞれのクライアントのTLSクライアント証明書
FAPI-CIBAテスト時の追加要件
CIBAテストではユーザーがデバイスで認証を承認する必要がある:
# CIBAデバイス認証シミュレーション(テスト中に手動実行)
cd config/examples/financial-grade
./ciba-device-auth.sh
このスクリプトはCIBAバックチャネル認証リクエストに対して、ユーザーの認証承認をシミュレートする。
Gap分析ドキュメント
documentation/requirements/fapi-1.0-gap-analysis.yaml にOIDF適合性テスト結果と修正記録を管理:
- 各GAP項目のID、仕様参照、修正状態、修正内容を記録
- テナント設定・クライアント設定の要件充足分析も含む
- 新しいGAPが見つかった場合はこのファイルに追記する
トラブルシューティング
PKCE S256エラー
code_challenge_method=S256のみ許可(plainは不可)- FAPI Baselineでは必須
PAR request_uri無効
- request_uriの有効期限(90秒)を確認
- 使用済みrequest_uriは再利用不可
mTLS証明書検証失敗
- クライアント証明書が正しく送信されているか確認
TlsClientAuthAuthenticatorの設定を確認
JARM署名検証失敗
- Authorization Serverの署名鍵(JWK)を確認
responseパラメータのJWT形式を確認
OIDFテスト discoveryUrl エラー
discoveryUrlがapi.local.dev(通常エンドポイント)を指しているか確認resourceUrlがmtls.api.local.dev(mTLSエンドポイント)を指しているか確認host.docker.internal:8445等の旧URL形式が残っていないか確認
Recommended Agent Skills
Expand your agent's capabilities with these related and highly-rated skills.
agent-ops-spec
Manage specification documents in .agent/specs/. Use when user provides requirements, acceptance criteria, or feature descriptions that need to be tracked and validated against implementation.
agent-ops-state
Maintain .agent state files. Use at session start, after meaningful steps, and before concluding: read/update constitution/memory/focus/issues/baseline consistently.
agent-ops-spec
Manage specification documents in .agent/specs/. Use when user provides requirements, acceptance criteria, or feature descriptions that need to be tracked and validated against implementation.
agent-ops-testing
Test strategy, execution, and coverage analysis. Use when designing tests, running test suites, or analyzing test results beyond baseline checks.
agent-ops-testing
Test strategy, execution, and coverage analysis. Use when designing tests, running test suites, or analyzing test results beyond baseline checks.
agent-ops-state
Maintain .agent state files. Use at session start, after meaningful steps, and before concluding: read/update constitution/memory/focus/issues/baseline consistently.
Didn't find tool you were looking for?