メインコンテンツまでスキップ

FAPI CIBA Profile - プロトコル仕様

概要

FAPI CIBA (Financial-grade API: Client Initiated Backchannel Authentication) Profile は、金融グレードのセキュリティを備えたバックチャネル認証を実現するためのプロファイルです。

idp-serverは OpenID FAPI CIBA Security Profile に完全準拠しており、以下の3つの仕様を組み合わせています:

  • FAPI Part 1 (Baseline): 読み取り専用APIの基本セキュリティ
  • FAPI Part 2 (Advanced): 書き込みAPIの高度なセキュリティ
  • CIBA Core: バックチャネル認証フロー

ユースケース

FAPI CIBAは以下のような高セキュリティが要求されるシナリオで使用されます:

ユースケース説明具体例
オープンバンキングPSD2準拠の金融API口座情報参照、送金実行
デバイス分離認証操作端末と認証端末が異なるATM送金、コールセンター認証
リモート承認別デバイスでの認証承認スマホでのプッシュ通知承認
高額取引金融取引の多要素認証大口送金、証券取引

FAPI CIBA vs 標準CIBA

セキュリティ要件比較

項目標準CIBAFAPI CIBA
リクエストオブジェクト任意必須(署名付き)
署名アルゴリズムRS256等も可PS256/ES256のみ
リクエスト有効期限制限なし最大60分
クライアント認証client_secret系も可private_key_jwt, mTLS のみ
binding_message任意authorization_details未使用時は必須
トークン配信モードpush/poll/pingpoll/pingのみ(push禁止)
トークンバインディング任意Sender-constrained必須(mTLS)
aud claim任意必須(Issuer URL含む)

プロトコルフロー

1. バックチャネル認証リクエスト

POST /backchannel/authentications HTTP/1.1
Host: idp-server.example.com
Content-Type: application/x-www-form-urlencoded

request=eyJhbGciOiJQUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6InNlbGZfcmVxdWVzdF9rZXlfcHMyNTYifQ...
&client_id=fapi-ciba-client

リクエストオブジェクト(JWT)の内容:

{
"alg": "PS256",
"kid": "self_request_key_ps256"
}
.
{
"scope": "openid payment_initiation",
"binding_message": "TX-12345: €500 to ACME Corp",
"user_code": "123456",
"login_hint": "device:auth_device_id,idp:idp-server",
"authorization_details": [
{
"type": "payment_initiation",
"instructedAmount": {
"currency": "EUR",
"amount": "500.00"
},
"creditorName": "ACME Corp",
"creditorAccount": {
"iban": "DE02100100109307118603"
}
}
],
"client_id": "fapi-ciba-client",
"aud": "https://idp-server.example.com",
"iss": "fapi-ciba-client",
"exp": 1234567890,
"iat": 1234564290,
"nbf": 1234564290,
"jti": "unique-request-id"
}

レスポンス:

{
"auth_req_id": "ea2856d7-9aab-40c6-ae71-f8db93602eab",
"expires_in": 600,
"interval": 5
}

2. 認証デバイスでの承認

ユーザーはスマートフォン等の認証デバイスでプッシュ通知を受け取り、以下の情報を確認:

  • binding_message: "TX-12345: €500 to ACME Corp"
  • authorization_details: 支払い詳細(金額、送金先等)

生体認証(FIDO-UAF)またはパスワードで承認します。

3. トークンリクエスト(ポーリング)

POST /tokens HTTP/1.1
Host: idp-server.example.com
Content-Type: application/x-www-form-urlencoded
SSL-Client-Cert: <client-certificate>

grant_type=urn:openid:params:grant-type:ciba
&auth_req_id=ea2856d7-9aab-40c6-ae71-f8db93602eab
&client_id=fapi-ciba-client

レスポンス:

{
"access_token": "eyJhbGc...",
"id_token": "eyJhbGc...",
"token_type": "Bearer",
"expires_in": 3600,
"refresh_token": "refresh..."
}

アクセストークン(JWT)の内容:

{
"iss": "https://idp-server.example.com",
"sub": "user-123",
"aud": "resource-server",
"exp": 1234567890,
"iat": 1234564290,
"scope": "openid payment_initiation",
"cnf": {
"x5t#S256": "bwcK0esc3ACC3DB2Y5_lESsXE8o9ltc05O89jdN-dg2"
}
}

重要: cnf:x5t#S256 がクライアント証明書のサムプリントで、mTLSバインディングを実現します。

FAPI要件マッピング

要件の階層構造

FAPI CIBAは 3つの仕様を積み重ねた構造 になっています:

┌─────────────────────────────────────────┐
│ FAPI CIBA 5.2.2 │ ← CIBA固有の追加要件
│ - binding_message要件 │
│ - Push mode禁止 │
│ - Signed request object必須 │
├─────────────────────────────────────────┤
│ FAPI Part 2 (Advanced) 5.2.2 │ ← Part 1の一部を上書き
│ - Client authentication制限(上書き) │
│ - Sender-constrained tokens必須 │
│ - Request object lifetime制限 │
├─────────────────────────────────────────┤
│ FAPI Part 1 (Baseline) 5.2.2 │ ← 基本セキュリティ要件
│ - Confidential client必須 │
│ - 鍵サイズ・エントロピー要件 │
│ - トークン推測不可能性 │
├─────────────────────────────────────────┤
│ 基本OIDC/OAuth 2.0 │ ← 標準プロトコル
└─────────────────────────────────────────┘

FAPI CIBA準拠 = すべての層の要件を満たす

重要な上書き関係

要件FAPI Part 1FAPI Part 2(上書き)最終適用
Client Authenticationprivate_key_jwt
client_secret_jwt
mTLS
private_key_jwt
client_secret_jwt
mTLS
Part 2が優先
secret系は禁止
PKCE必須(5.2.2-7)免除(CIBAには不適用)Part 2が優先
CIBA不要

FAPI Part 1 (Baseline) 5.2.2 要件

#要件CIBA適用実装備考
1Confidential clients必須✅ 適用throwExceptionIfNotConfidentialClient()Public client禁止
2Public clients推奨❌ 不適用-FAPI CIBAはconfidentialのみ
3Client secret entropy (OIDC 16.19)✅ 適用-256/512 bit minimum
4Client authentication methods⚠️ 上書きthrowExceptionIfInvalidClientAuthenticationMethod()FAPI Part 2で変更
5RSA key ≥ 2048 bits✅ 適用JWKs検証Request object署名、private_key_jwt認証
6EC key ≥ 160 bits✅ 適用JWKs検証実際はES256(256 bits)が最小
7PKCE with S256❌ 不適用-CIBAにはauthorization codeなし
8Pre-register redirect_uri❌ 不適用-CIBAにはredirectなし
9Require redirect_uri in request❌ 不適用-同上
10Exact match redirect_uri❌ 不適用-同上
11User authentication LoA✅ 適用Authentication Policy認証ポリシーで制御
12Explicit user approval✅ 適用-binding_message/authorization_details
13Reject reused authorization code❌ 不適用-CIBAにはcodeなし
14Token response format (RFC6749 4.1.4)✅ 適用-標準準拠
15Return granted scopes (front channel)❌ 不適用-CIBAはbackchannel
16Non-guessable tokens (RFC6749 10.10)✅ 適用-auth_req_id, tokens
17Grant details disclosure (OIDC 16.18)✅ 適用-binding_message
18Token revocation (OIDC 16.18)✅ 適用-Revocation endpoint
19invalid_client for mismatched client_id✅ 適用-エラーハンドリング
20HTTPS redirect_uri❌ 不適用-CIBAにはredirectなし
21Access token lifetime < 10min⚠️ 推奨-Sender-constrainedなら任意
22OIDD support✅ 適用-Discovery必須

FAPI Part 2 (Advanced) 5.2.2 要件 - 完全版

FAPI Part 2 (Advanced) は 書き込みAPI向けの高度なセキュリティプロファイル で、PAR (Pushed Authorization Request)、JARM (JWT Secured Authorization Response Mode)、より強力なクライアント認証を追加しています。

CIBA適用時の注意: FAPI Part 2の多くの要件はフロントチャネル(authorization endpoint)向けですが、以下の要件がCIBAに適用されます。

Authorization Server要件(全18要件)

#FAPI Part 2 要件(原文)CIBA適用実装状況実装メソッド/場所備考
前提FAPI Part 1準拠(5.2.2-7除く)⚠️ 部分適用✅ 実装済み-PKCE要件(5.2.2-7)はCIBA不適用
5.2.2-1shall require a JWS signed JWT request object passed by value with the request parameter or by reference✅ 適用✅ 実装済みFapiCibaVerifier.throwExceptionIfNotSignedRequestObject()CIBAではrequestパラメータによる値渡しのみ(request_uriは不使用)
5.2.2-2shall require either response_type value code id_token OR code in conjunction with response_mode jwt❌ 不適用N/A-CIBAにはresponse_typeパラメータなし(backchannel)
5.2.2-5shall only issue sender-constrained access tokens✅ 適用✅ 実装済みFapiCibaVerifier.throwIfNotSenderConstrainedAccessToken()mTLSバインディング必須(cnf:x5t#S256
5.2.2-6shall support MTLS as mechanism for constraining the legitimate senders of access tokens✅ 適用✅ 実装済みmTLS証明書バインディングcnf:x5t#S256クレームによる証明書サムプリント
5.2.2-10shall only use the parameters included in the signed request object passed via request or request_uri✅ 適用✅ 実装済みFapiCibaVerifier.throwExceptionIfNotSignedRequestObject()署名済みrequest objectのみ使用、外部パラメータ無視
5.2.2-11may support pushed authorization request endpoint (PAR)❌ 不適用N/A-CIBAには/backchannel/authenticationsが専用エンドポイント(PAR不要)
5.2.2-13shall require the request object to contain an exp claim that has a lifetime of no longer than 60 minutes after nbf✅ 適用✅ 実装済みFapiCibaVerifier.throwExceptionIfInvalidRequestObjectLifetime()exp - nbf ≤ 60分
5.2.2-14shall authenticate confidential clients via MTLS or private_key_jwt methods適用✅ 実装済みFapiCibaVerifier.throwExceptionIfInvalidClientAuthenticationMethod()重要: Part 1の5.2.2-4を上書き(client_secret_jwt禁止)
5.2.2-15shall require the aud claim in the request object to be the OP's Issuer Identifier URL✅ 適用✅ 実装済みFapiCibaVerifier.throwExceptionIfNotContainsAud()audにIssuer URL含有を検証
5.2.2-16shall not support public clients✅ 適用✅ 実装済みFapiCibaVerifier.throwExceptionIfNotConfidentialClient()Confidential clientのみ許可
5.2.2-17shall require the request object to contain an nbf claim that is no longer than 60 minutes in the past✅ 適用✅ 実装済みFapiCibaVerifier.throwExceptionIfInvalidRequestObjectLifetime()now - nbf ≤ 60分
5.2.2-18shall require PAR requests to use PKCE with S256 as the code challenge method❌ 不適用N/A-CIBAにはPAR不要(5.2.2-11参照)

CIBA適用要件のみ抽出(8要件)

#FAPI Part 2 要件実装状況実装メソッドテストケース
5.2.2-1JWS signed request object必須✅ 実装済みthrowExceptionIfNotSignedRequestObject()fapi_ciba.test.js 署名検証テスト
5.2.2-5Sender-constrained tokens必須✅ 実装済みthrowIfNotSenderConstrainedAccessToken()Test #21: cnf:x5t#S256検証
5.2.2-6MTLSサポート✅ 実装済みmTLS証明書バインディング全CIBA E2EテストでmTLS使用
5.2.2-10署名済みrequest objectのみ使用✅ 実装済みthrowExceptionIfNotSignedRequestObject()同5.2.2-1
5.2.2-13Request object lifetime ≤ 60min✅ 実装済みthrowExceptionIfInvalidRequestObjectLifetime()Test #8: exp-nbf検証
5.2.2-14Client authentication (上書き)✅ 実装済みthrowExceptionIfInvalidClientAuthenticationMethod()Test #9: 認証方式検証
5.2.2-15aud claim必須✅ 実装済みthrowExceptionIfNotContainsAud()FAPI Part 2 5.2.2-11テスト
5.2.2-16Public clients禁止✅ 実装済みthrowExceptionIfNotConfidentialClient()Test #2: confidential client検証
5.2.2-17nbf claim検証✅ 実装済みthrowExceptionIfInvalidRequestObjectLifetime()Test #10: nbf age検証

実装完了度サマリー

FAPI Part 2 (Advanced) 5.2.2要件: 全18要件
├─ CIBA適用: 9要件(前提1 + 本文8)
│ ├─ 実装済み: 9要件 (100%)
│ ├─ 未実装: 0要件
│ └─ テストカバレッジ: 9/9 (100%)
└─ CIBA不適用: 9要件
└─ 理由: フロントチャネル専用(authorization endpoint、PAR等)

結論: FAPI Part 2 (Advanced) のCIBA適用要件は 完全実装済み です。

5.2.2-14: Client Authentication Methods(重要な上書き)

FAPI Part 1 (5.2.2-4): 以下のいずれかを許可

  • private_key_jwt
  • client_secret_jwt
  • mTLS (tls_client_auth, self_signed_tls_client_auth)

FAPI Part 2 (5.2.2-14): 以下のみ許可(client_secret_jwt禁止

  • private_key_jwt
  • mTLS (tls_client_auth, self_signed_tls_client_auth) ✅

実装:

void throwExceptionIfInvalidClientAuthenticationMethod(CibaRequestContext context) {
ClientAuthenticationType authenticationType = context.clientAuthenticationType();

boolean isValid =
authenticationType.isPrivateKeyJwt()
|| authenticationType.isTlsClientAuth()
|| authenticationType.isSelfSignedTlsClientAuth();

if (!isValid) {
throw new BackchannelAuthenticationUnauthorizedException(
"invalid_client",
String.format(
"FAPI CIBA Profile requires client authentication method to be one of: private_key_jwt, tls_client_auth, self_signed_tls_client_auth. Current method: %s",
authenticationType.name()));
}
}

エラー例:

HTTP/1.1 401 Unauthorized
Content-Type: application/json

{
"error": "invalid_client",
"error_description": "FAPI CIBA Profile requires client authentication method to be one of: private_key_jwt, tls_client_auth, self_signed_tls_client_auth. Current method: client_secret_post"
}

FAPI CIBA 5.2.2 固有要件

#要件実装HTTPステータス
1Signed request object必須throwExceptionIfNotSignedRequestObject()400
2Request object lifetime ≤ 60minthrowExceptionIfInvalidRequestObjectLifetime()400
3Signing algorithm PS256/ES256throwExceptionIfInvalidSigningAlgorithm()400
4Confidential clientsthrowExceptionIfNotConfidentialClient()401
5binding_message (条件付き)throwExceptionIfMissingBindingMessage()400
6Push mode禁止throwExceptionIfPushMode()400
7Client authentication restrictionsthrowExceptionIfInvalidClientAuthenticationMethod()401
11aud claim必須throwExceptionIfNotContainsAud()400
-Sender-constrained tokensthrowIfNotSenderConstrainedAccessToken()400

エラーレスポンス

invalid_client (HTTP 401)

CIBA Core Section 13準拠: クライアント認証失敗は401を返す

{
"error": "invalid_client",
"error_description": "FAPI CIBA Profile requires client authentication method to be one of: private_key_jwt, tls_client_auth, self_signed_tls_client_auth. Current method: client_secret_post"
}

invalid_request (HTTP 400)

{
"error": "invalid_request",
"error_description": "FAPI CIBA Profile requires request object lifetime to be no longer than 60 minutes. Current lifetime: 75 minutes"
}

mTLS トークンバインディング

Sender-constrained Access Tokens

FAPI CIBAでは、アクセストークンをクライアント証明書にバインドすることが必須です。

1. トークン発行時

クライアント → nginx (mTLS終端) → idp-server
(mTLS) (HTTP + X-SSL-Cert header)

1. nginx: クライアント証明書検証
2. nginx: 証明書をPEMエンコードしてHTTPヘッダーで転送
3. idp-server: 証明書サムプリント(SHA-256)計算
4. idp-server: cnf:x5t#S256 としてアクセストークンに埋め込み

2. API呼び出し時

クライアント → nginx (mTLS終端) → Resource Server
(mTLS) (HTTP + X-SSL-Cert + Authorization)

1. nginx: クライアント証明書検証
2. Resource Server: トークン内 cnf:x5t#S256 抽出
3. Resource Server: 証明書サムプリント計算
4. Resource Server: 一致確認 → アクセス許可

重要: トークンと証明書の両方が揃わないとAPIアクセス不可

証明書サムプリントの計算

# 証明書からサムプリント取得
openssl x509 -in client-cert.pem -noout -fingerprint -sha256 | \
cut -d= -f2 | tr -d ':' | xxd -r -p | base64 | tr '+/' '-_' | tr -d '='

# 結果例
bwcK0esc3ACC3DB2Y5_lESsXE8o9ltc05O89jdN-dg2

実装チェックリスト

サーバー設定

  • token_endpoint_auth_methods_supportedprivate_key_jwt, tls_client_auth, self_signed_tls_client_auth のみ含む
  • grant_types_supportedurn:openid:params:grant-type:ciba 含む
  • backchannel_token_delivery_modes_supportedpoll, ping のみ含む(push 除外)
  • backchannel_authentication_request_signing_alg_values_supportedPS256, ES256 含む
  • tls_client_certificate_bound_access_tokenstrue に設定
  • authorization_details_types_supported に対応する型を定義

クライアント設定

  • token_endpoint_auth_methodprivate_key_jwt, tls_client_auth, self_signed_tls_client_auth のいずれかに設定
  • grant_typesurn:openid:params:grant-type:ciba 含む
  • backchannel_token_delivery_modepoll または ping に設定
  • backchannel_authentication_request_signing_algPS256 または ES256 に設定
  • tls_client_certificate_bound_access_tokenstrue に設定
  • jwks に PS256/ES256対応の公開鍵を登録

インフラ設定

  • nginx/AWS ALBでmTLS終端を設定
  • クライアント証明書をHTTPヘッダー(X-SSL-Cert)で転送
  • 証明書検証ロジック実装
  • BFF Serverでクライアント証明書を安全に管理(ネイティブアプリの場合)

セキュリティ考慮事項

1. 暗号鍵の要件

鍵長の最小要件(FAPI Part 1 5.2.2-5, 5.2.2-6)

FAPI CIBAでは、すべての署名・認証に使用する鍵が以下の鍵長要件を満たす必要があります:

アルゴリズム鍵タイプ最小鍵長推奨鍵長用途
RS256, RS384, RS512RSA2048 bits3072 bitsRequest object署名、private_key_jwt、ID Token署名
PS256, PS384, PS512RSA-PSS2048 bits3072 bits同上(FAPI CIBAで推奨)
ES256ECDSA (P-256)256 bits256 bitsRequest object署名、private_key_jwt
ES384ECDSA (P-384)384 bits384 bits同上
ES512ECDSA (P-521)521 bits521 bits同上

適用箇所:

  1. クライアントのJWKsjwks / jwks_uri登録)

    • Request object署名用の鍵
    • private_key_jwt認証用の鍵
  2. Authorization ServerのJWKs

    • ID Token署名用の鍵
    • Access Token署名用の鍵(JWT形式の場合)

鍵生成例:

# RSA 2048 bits(最小)
openssl genrsa -out private-key.pem 2048

# RSA 3072 bits(推奨)
openssl genrsa -out private-key.pem 3072

# ECDSA P-256(ES256用)
openssl ecparam -genkey -name prime256v1 -out private-key.pem

# ECDSA P-384(ES384用)
openssl ecparam -genkey -name secp384r1 -out private-key.pem

注意: 仕様上は「楕円曲線160 bits以上」ですが、実際にはES256(256 bits)が最小の安全な鍵長です。

2. リクエストオブジェクト署名検証

  • 必須: PS256/ES256署名(RSA ≥ 2048 bits, EC ≥ 256 bits)
  • 必須: nbf/exp検証(最大60分)
  • 必須: aud claim検証(Issuer URL含む)
  • 推奨: jti (JWT ID) でリプレイ攻撃防止

3. クライアント認証

  • 禁止: client_secret_basic, client_secret_post, client_secret_jwt
  • 必須: private_key_jwt(鍵長要件満たすこと)または mTLS
  • 推奨: クライアント証明書のローテーション(最大1年)

4. トークンバインディング

  • 必須: Sender-constrained access tokens (mTLS binding)
  • 必須: cnf:x5t#S256 クレーム
  • 推奨: トークン有効期限を短く設定(10分以下)

5. Authorization Details

  • 推奨: 細かい権限制御にauthorization_details使用
  • 推奨: authorization_details使用時はbinding_message省略可能
  • 必須: ユーザーに承認内容を明確に表示

パフォーマンス考慮事項

項目推奨値理由
auth_req_id有効期限10分ユーザー操作時間を考慮
ポーリング間隔5秒サーバー負荷とUX のバランス
アクセストークン有効期限10分以下Sender-constrainedなら短く
リフレッシュトークン推奨長時間セッション維持

関連ドキュメント

仕様書

idp-server ドキュメント


作成日: 2025-11-29 対象: システムアーキテクト、セキュリティエンジニア 習得スキル: FAPI CIBA Profile完全理解、金融グレードAPI実装