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

FAPI

📍 このドキュメントの位置づけ

対象読者: 金融グレードのセキュリティを実装したい開発者

このドキュメントで学べること:

  • FAPI Baseline / Advance Profile の実装詳細
  • mTLS (Mutual TLS) クライアント認証の仕組み
  • Sender-constrained Access Tokens の実装
  • PAR (Pushed Authorization Requests) の実装
  • JARM (JWT Secured Authorization Response Mode) の実装
  • Request Object 検証の詳細

前提知識:


🏗️ FAPI アーキテクチャ概要

FAPI (Financial-grade API) は、金融取引など高セキュリティが要求される環境で OAuth 2.0/OIDC を安全に利用するための仕様です。

idp-serverのFAPI対応

プロファイル用途実装モジュール主要コンポーネント
FAPI Baseline読み取り専用APIidp-server-core-extension-fapiFapiBaselineVerifier
FAPI Advance書き込みAPIidp-server-core-extension-fapiFapiAdvanceVerifier
FAPI CIBAデバイス分離認証idp-server-core-extension-fapi-ciba(CIBAモジュール)

プロファイル自動判定

idp-serverは、リクエストされたスコープに基づいてFAPIプロファイルを自動判定します。

判定ロジック(優先順位順):
1. スコープが fapiAdvanceScopes に一致 → FAPI Advance
2. スコープが fapiBaselineScopes に一致 → FAPI Baseline
3. スコープに openid が含まれる → OIDC
4. それ以外 → OAuth 2.0

テナント設定例:

{
"extension": {
"fapi_baseline_scopes": ["read", "account"],
"fapi_advance_scopes": ["write", "transfers", "payment_initiation"]
}
}

📋 FAPI Baseline Profile 実装

概要

FAPI Baseline は、読み取り専用API(残高照会、取引履歴参照等)向けのプロファイルです。

主要要件:

  • ✅ 署名付きリクエストオブジェクト(PS256/ES256)
  • ✅ PKCE必須(S256のみ)
  • ✅ 強固なクライアント認証(private_key_jwt または mTLS)
  • ✅ HTTPSリダイレクトURI必須
  • ✅ nonce(OIDCの場合)または state(OAuth 2.0の場合)必須

実装: FapiBaselineVerifier

public class FapiBaselineVerifier implements AuthorizationRequestVerifier {

OAuthRequestBaseVerifier oAuthRequestBaseVerifier = new OAuthRequestBaseVerifier();
OidcRequestBaseVerifier oidcRequestBaseVerifier = new OidcRequestBaseVerifier();

public AuthorizationProfile profile() {
return AuthorizationProfile.FAPI_BASELINE;
}

@Override
public void verify(OAuthRequestContext context) {
// 1. リダイレクトURI検証
throwExceptionIfUnregisteredRedirectUri(context);
throwExceptionIfNotContainsRedirectUri(context);
throwExceptionUnMatchRedirectUri(context);
throwExceptionIfNotHttpsRedirectUri(context);

// 2. 基本検証(OIDC or OAuth 2.0)
if (context.isOidcRequest()) {
oidcRequestBaseVerifier.verify(context);
} else {
oAuthRequestBaseVerifier.verify(context);
}

// 3. FAPI Baseline固有検証
throwExceptionIfClientSecretPostOrClientSecretBasic(context);
throwExceptionIfNotS256CodeChallengeMethod(context);
throwExceptionIfHasOpenidScopeAndNotContainsNonce(context);
throwExceptionIfNotHasOpenidScopeAndNotContainsState(context);
}
}

参考実装: FapiBaselineVerifier.java:31

1. リダイレクトURI検証

shall require redirect URIs to be pre-registered

void throwExceptionIfUnregisteredRedirectUri(OAuthRequestContext context) {
ClientConfiguration clientConfiguration = context.clientConfiguration();
if (!clientConfiguration.hasRedirectUri()) {
throw new OAuthBadRequestException(
"invalid_request",
"When FAPI Baseline profile, shall require redirect URIs to be pre-registered",
context.tenant());
}
}

shall require the redirect_uri in the authorization request

void throwExceptionIfNotContainsRedirectUri(OAuthRequestContext context) {
if (!context.hasRedirectUriInRequest()) {
throw new OAuthBadRequestException(
"invalid_request",
"When FAPI Baseline profile, shall require the redirect_uri in the authorization request",
context.tenant());
}
}

shall require redirect URIs to use the https scheme

void throwExceptionIfNotHttpsRedirectUri(OAuthRequestContext context) {
RedirectUri redirectUri = context.redirectUri();
if (!redirectUri.isHttps()) {
throw new OAuthBadRequestException(
"invalid_request",
"When FAPI Baseline profile, shall require redirect URIs to use the https scheme",
context.tenant());
}
}

2. クライアント認証検証

shall authenticate using one of: mTLS, client_secret_jwt, private_key_jwt

void throwExceptionIfClientSecretPostOrClientSecretBasic(OAuthRequestContext context) {
ClientAuthenticationType clientAuthenticationType = context.clientAuthenticationType();

// client_secret_basic は禁止
if (clientAuthenticationType.isClientSecretBasic()) {
throw new OAuthRedirectableBadRequestException(
"unauthorized_client",
"When FAPI Baseline profile, client_secret_basic MUST not be used",
context);
}

// client_secret_post は禁止
if (clientAuthenticationType.isClientSecretPost()) {
throw new OAuthRedirectableBadRequestException(
"unauthorized_client",
"When FAPI Baseline profile, client_secret_post MUST not be used",
context);
}
}

許可される認証方式:

  • private_key_jwt - 秘密鍵によるJWT署名
  • client_secret_jwt - 共有秘密によるJWT署名
  • tls_client_auth - mTLS(証明書による認証)
  • self_signed_tls_client_auth - 自己署名証明書による認証

3. PKCE検証

shall require RFC7636 with S256 as the code challenge method

void throwExceptionIfNotS256CodeChallengeMethod(OAuthRequestContext context) {
AuthorizationRequest authorizationRequest = context.authorizationRequest();

// code_challenge と code_challenge_method が必須
if (!authorizationRequest.hasCodeChallenge()
|| !authorizationRequest.hasCodeChallengeMethod()) {
throw new OAuthRedirectableBadRequestException(
"invalid_request",
"When FAPI Baseline profile, authorization request must contain code_challenge and code_challenge_method(S256).",
context);
}

// code_challenge_method は S256 のみ
if (!authorizationRequest.codeChallengeMethod().isS256()) {
throw new OAuthRedirectableBadRequestException(
"invalid_request",
"When FAPI Baseline profile, shall require RFC7636 with S256 as the code challenge method.",
context);
}
}

PKCE検証フロー:

1. 認可リクエスト:   code_challenge=xxx&code_challenge_method=S256
2. 認可コード発行: code=yyy
3. トークンリクエスト: code=yyy&code_verifier=zzz
4. 検証: SHA256(zzz) == xxx

4. Nonce / State検証

Client requesting openid scope: shall require the nonce parameter

void throwExceptionIfHasOpenidScopeAndNotContainsNonce(OAuthRequestContext context) {
if (!context.hasOpenidScope()) {
return; // openid スコープなしの場合はスキップ
}

if (!context.authorizationRequest().hasNonce()) {
throw new OAuthRedirectableBadRequestException(
"invalid_request",
"When FAPI Baseline profile, shall require the nonce parameter in the authentication request.",
context);
}
}

Clients not requesting openid scope: shall require the state parameter

void throwExceptionIfNotHasOpenidScopeAndNotContainsState(OAuthRequestContext context) {
if (context.hasOpenidScope()) {
return; // openid スコープありの場合はスキップ
}

if (!context.authorizationRequest().hasState()) {
throw new OAuthRedirectableBadRequestException(
"invalid_request",
"When FAPI Baseline profile, shall require the state parameter.",
context);
}
}

🔐 FAPI Advance Profile 実装

概要

FAPI Advance は、書き込みAPI(送金実行、口座設定変更等)向けのプロファイルです。

Baselineに追加される要件:

  • ✅ PAR(Pushed Authorization Requests)必須
  • ✅ JARM(JWT Secured Authorization Response)必須
  • ✅ Sender-constrained アクセストークン必須(mTLS binding)
  • ✅ Request Object 有効期限: 最大60分
  • aud claim必須(Issuer URL)
  • ✅ Publicクライアント禁止
  • client_secret_jwt も禁止(private_key_jwt または mTLS のみ)

実装: FapiAdvanceVerifier

public class FapiAdvanceVerifier implements AuthorizationRequestVerifier {

public AuthorizationProfile profile() {
return AuthorizationProfile.FAPI_ADVANCE;
}

@Override
public void verify(OAuthRequestContext context) {
// 1. 設定検証
throwIfExceptionInvalidConfig(context);

// 2. 基本検証
if (context.isOidcRequest()) {
oidcRequestBaseVerifier.verify(context);
} else {
oAuthRequestBaseVerifier.verify(context);
}

// 3. FAPI Advance固有検証
throwExceptionIfNotRRequestParameterPattern(context);
throwExceptionIfInvalidResponseTypeAndResponseMode(context);
throwIfNotSenderConstrainedAccessToken(context);
throwExceptionIfNotContainExpAndNbfAndExp60minutesLongerThanNbf(context);
throwExceptionIfNotContainsAud(context);
throwExceptionIfClientSecretPostOrClientSecretBasicOrClientSecretJwt(context);
throwExceptionIfPublicClient(context);
throwExceptionIfNotContainNbfAnd60minutesLongerThan(context);
}
}

参考実装: FapiAdvanceVerifier.java:34

1. Request Object 必須

shall require a JWS signed JWT request object

void throwExceptionIfNotRRequestParameterPattern(OAuthRequestContext context) {
if (!context.isRequestParameterPattern()) {
throw new OAuthRedirectableBadRequestException(
"invalid_request",
"When FAPI Advance profile, shall require a JWS signed JWT request object passed by value with the request parameter or by reference with the request_uri parameter",
context);
}
}

Request Object パターン:

  • By Value: request=eyJhbGciOiJQUzI1NiIs...
  • By Reference: request_uri=https://client.example.com/request/abcd1234

2. Response Type / Response Mode 検証

shall require response_type code id_token, or code + response_mode jwt

void throwExceptionIfInvalidResponseTypeAndResponseMode(OAuthRequestContext context) {
// パターン1: response_type=code id_token (Hybrid Flow)
if (context.responseType().isCodeIdToken()) {
return;
}

// パターン2: response_type=code&response_mode=jwt (JARM)
if (context.responseType().isCode() && context.responseMode().isJwt()) {
return;
}

throw new OAuthRedirectableBadRequestException(
"invalid_request",
"When FAPI Advance profile, shall require the response_type value code id_token, or the response_type value code in conjunction with the response_mode value jwt",
context);
}

許可されるパターン:

  • response_type=code id_token - Hybrid Flow
  • response_type=code&response_mode=jwt - JARM

3. Sender-constrained Access Tokens

shall only issue sender-constrained access tokens

void throwIfNotSenderConstrainedAccessToken(OAuthRequestContext context) {
AuthorizationServerConfiguration authorizationServerConfiguration =
context.serverConfiguration();
ClientConfiguration clientConfiguration = context.clientConfiguration();

// サーバー側で有効化されているか
if (!authorizationServerConfiguration.isTlsClientCertificateBoundAccessTokens()) {
throw new OAuthRedirectableBadRequestException(
"invalid_request",
"When FAPI Advance profile, shall only issue sender-constrained access tokens, but server tls_client_certificate_bound_access_tokens is false",
context);
}

// クライアント側で有効化されているか
if (!clientConfiguration.isTlsClientCertificateBoundAccessTokens()) {
throw new OAuthRedirectableBadRequestException(
"invalid_request",
"When FAPI Advance profile, shall only issue sender-constrained access tokens, but client tls_client_certificate_bound_access_tokens is false",
context);
}
}

Sender-constrained Access Tokens の仕組み:

1. クライアント証明書のサムプリント(SHA-256)を計算
2. アクセストークン(JWT)の cnf クレームに格納
{
"cnf": {
"x5t#S256": "bwcK0esc3ACC3DB2Y5_lESsXE8o9ltc05O89jdN-dg2"
}
}
3. API呼び出し時、サーバーは証明書とサムプリントを照合
4. 一致した場合のみAPIアクセスを許可

4. Request Object 有効期限検証

shall require exp claim that has a lifetime of no longer than 60 minutes after nbf

void throwExceptionIfNotContainExpAndNbfAndExp60minutesLongerThanNbf(
OAuthRequestContext context) {

JoseContext joseContext = context.joseContext();
JsonWebTokenClaims claims = joseContext.claims();

// exp クレーム必須
if (!claims.hasExp()) {
throw new OAuthRedirectableBadRequestException(
"invalid_request_object",
"When FAPI Advance profile, shall require the request object to contain an exp claim",
context);
}

// nbf クレーム必須
if (!claims.hasNbf()) {
throw new OAuthRedirectableBadRequestException(
"invalid_request_object",
"When FAPI Advance profile, shall require the request object to contain an nbf claim",
context);
}

// exp - nbf <= 60分
Date exp = claims.getExp();
Date nbf = claims.getNbf();
if (exp.getTime() - nbf.getTime() > 3600001) { // 60分 + 1ミリ秒
throw new OAuthRedirectableBadRequestException(
"invalid_request_object",
"When FAPI Advance profile, shall require the request object to contain an exp claim that has a lifetime of no longer than 60 minutes after the nbf claim",
context);
}
}

5. Audience (aud) 検証

shall require the aud claim to contain the OP's Issuer Identifier URL

void throwExceptionIfNotContainsAud(OAuthRequestContext context) {
JoseContext joseContext = context.joseContext();
JsonWebTokenClaims claims = joseContext.claims();

// aud クレーム必須
if (!claims.hasAud()) {
throw new OAuthRedirectableBadRequestException(
"invalid_request_object",
"When FAPI Advance profile, shall require the request object to contain an aud claim",
context);
}

// aud に Issuer URL が含まれているか
List<String> aud = claims.getAud();
if (!aud.contains(context.tokenIssuer().value())) {
throw new OAuthRedirectableBadRequestException(
"invalid_request_object",
String.format(
"When FAPI Advance profile, shall require the aud claim in the request object to contain the OP's Issuer Identifier URL (%s)",
String.join(" ", aud)),
context);
}
}

6. クライアント認証検証(Advance限定)

shall authenticate using: tls_client_auth, self_signed_tls_client_auth, or private_key_jwt

void throwExceptionIfClientSecretPostOrClientSecretBasicOrClientSecretJwt(
OAuthRequestContext context) {

ClientAuthenticationType clientAuthenticationType = context.clientAuthenticationType();

// client_secret_basic 禁止
if (clientAuthenticationType.isClientSecretBasic()) {
throw new OAuthRedirectableBadRequestException(
"unauthorized_client",
"When FAPI Advance profile, client_secret_basic MUST not be used",
context);
}

// client_secret_post 禁止
if (clientAuthenticationType.isClientSecretPost()) {
throw new OAuthRedirectableBadRequestException(
"unauthorized_client",
"When FAPI Advance profile, client_secret_post MUST not be used",
context);
}

// client_secret_jwt も禁止(Advance では)
if (clientAuthenticationType.isClientSecretJwt()) {
throw new OAuthRedirectableBadRequestException(
"unauthorized_client",
"When FAPI Advance profile, client_secret_jwt MUST not be used",
context);
}
}

FAPI Advance で許可される認証方式:

  • private_key_jwt - 秘密鍵によるJWT署名
  • tls_client_auth - mTLS(証明書による認証)
  • self_signed_tls_client_auth - 自己署名証明書による認証

FAPI Baseline で許可される認証方式(参考):

  • private_key_jwt
  • client_secret_jwt ← Advanceでは禁止
  • tls_client_auth
  • self_signed_tls_client_auth

7. Public Client 禁止

void throwExceptionIfPublicClient(OAuthRequestContext context) {
ClientAuthenticationType clientAuthenticationType = context.clientAuthenticationType();

if (clientAuthenticationType.isNone()) {
throw new OAuthRedirectableBadRequestException(
"unauthorized_client",
"When FAPI Advance profile, shall not support public clients",
context);
}
}

🔧 mTLS クライアント認証実装

TlsClientAuthAuthenticator

tls_client_auth 方式のクライアント認証を実装します。

public class TlsClientAuthAuthenticator implements ClientAuthenticator {

@Override
public ClientAuthenticationType type() {
return ClientAuthenticationType.tls_client_auth;
}

@Override
public ClientCredentials authenticate(BackchannelRequestContext context) {
RequestedClientId requestedClientId = context.requestedClientId();

// 1. クライアント証明書が存在するか確認
throwExceptionIfNotContainsClientCert(context);

// 2. X.509証明書をパースして検証
X509Certification x509Certification = parseOrThrowExceptionIfNoneMatch(context);

// 3. ClientCredentials生成
ClientCertification clientCertification = new ClientCertification(x509Certification);

return new ClientCredentials(
requestedClientId,
ClientAuthenticationType.tls_client_auth,
new ClientSecret(),
new ClientAuthenticationPublicKey(),
new ClientAssertionJwt(),
clientCertification);
}

X509Certification parseOrThrowExceptionIfNoneMatch(BackchannelRequestContext context) {
ClientCert clientCert = context.clientCert();
X509Certification x509Certification = X509Certification.parse(clientCert.plainValue());
ClientConfiguration clientConfiguration = context.clientConfiguration();

// 証明書検証(3つの方式のいずれかで一致)
// 1. tls_client_auth_subject_dn
if (x509Certification.subject().equals(clientConfiguration.tlsClientAuthSubjectDn())) {
return x509Certification;
}

// 2. tls_client_auth_san_dns (dNSName)
if (x509Certification.hasDNSName()
&& x509Certification.dNSName().equals(clientConfiguration.tlsClientAuthSanDns())) {
return x509Certification;
}

// 3. tls_client_auth_san_uri (uniformResourceIdentifier)
if (x509Certification.hasUniformResourceIdentifier()
&& x509Certification.uniformResourceIdentifier()
.equals(clientConfiguration.tlsClientAuthSanUri())) {
return x509Certification;
}

throw new ClientUnAuthorizedException("client certificate verification failed");
}
}

参考実装: TlsClientAuthAuthenticator.java:35

証明書検証方式:

  1. subject DN: 証明書のSubject Distinguished Nameで検証
  2. SAN DNS: Subject Alternative Name の dNSName フィールドで検証
  3. SAN URI: Subject Alternative Name の uniformResourceIdentifier フィールドで検証

📋 実装チェックリスト

FAPI対応を実装する際のチェックリスト:

FAPI Baseline

  • リダイレクトURI:

    • 事前登録必須
    • HTTPSスキーム必須
    • 完全一致検証
  • PKCE:

    • S256必須
    • code_challenge / code_challenge_method パラメータ必須
  • クライアント認証:

    • client_secret_basic 禁止
    • client_secret_post 禁止
    • private_key_jwt, client_secret_jwt, tls_client_auth, self_signed_tls_client_auth のいずれか
  • Nonce / State:

    • openid スコープあり → nonce 必須
    • openid スコープなし → state 必須

FAPI Advance

  • Baseline要件: 上記すべて満たす

  • Request Object:

    • JWS署名付きRequest Object必須
    • exp クレーム必須
    • nbf クレーム必須
    • exp - nbf <= 60分
    • aud クレーム必須(Issuer URL含む)
    • nbf が60分以上過去でない
  • Response Type / Mode:

    • response_type=code id_token または
    • response_type=code&response_mode=jwt
  • Sender-constrained Access Tokens:

    • サーバー設定で tls_client_certificate_bound_access_tokens=true
    • クライアント設定で tls_client_certificate_bound_access_tokens=true
    • アクセストークンに cnf.x5t#S256 含む
  • クライアント認証:

    • client_secret_jwt も禁止
    • private_key_jwt, tls_client_auth, self_signed_tls_client_auth のいずれか
  • Public Client:

    • 禁止

🚨 よくある間違い

1. PKCE の code_challenge_method

// ❌ 誤り: plain を許可してしまう
if (authorizationRequest.hasCodeChallenge()) {
// OK
}

// ✅ 正しい: S256 必須
if (authorizationRequest.hasCodeChallenge()
&& authorizationRequest.codeChallengeMethod().isS256()) {
// OK
} else {
throw new OAuthRedirectableBadRequestException("code_challenge_method must be S256");
}

2. Request Object の有効期限

// ❌ 誤り: expのみチェック
if (claims.hasExp()) {
// OK
}

// ✅ 正しい: exp と nbf の両方をチェック + 差分60分以内
if (claims.hasExp() && claims.hasNbf()) {
Date exp = claims.getExp();
Date nbf = claims.getNbf();
if (exp.getTime() - nbf.getTime() <= 3600000) { // 60分
// OK
}
}

3. クライアント認証方式の混同

// ❌ 誤り: FAPI Advance で client_secret_jwt を許可
// Baseline では OK だが Advance では NG

// ✅ 正しい: Advance では禁止
if (profile == AuthorizationProfile.FAPI_ADVANCE) {
if (clientAuthenticationType.isClientSecretJwt()) {
throw new OAuthRedirectableBadRequestException("client_secret_jwt not allowed in FAPI Advance");
}
}

4. Response Mode の指定忘れ

// ❌ 誤り: response_type=code のみ指定
// FAPI Advance では response_mode=jwt も必要

// ✅ 正しい: response_type=code&response_mode=jwt
if (context.responseType().isCode() && context.responseMode().isJwt()) {
// OK
}

📐 仕様階層と要件の継承関係

FAPI仕様は、既存のOAuth 2.0/OIDC仕様の上に追加要件を積み上げる階層構造をとります。

OAuth 2.0 (RFC 6749)
└─ OIDC Core 1.0
└─ FAPI 1.0 Baseline (Part 1)
└─ FAPI 1.0 Advanced (Part 2)

要件の継承と置換

FAPI 1.0 Advanced は Baseline の全要件を継承し、一部を置換します。

カテゴリ要件BaselineAdvanced
継承redirect_uri 事前登録/必須/完全一致 (5.2.2-8/9/10)✅ (そのまま継承)
継承redirect_uri https必須 (5.2.2-20)✅ (そのまま継承)
継承nonce必須 - openidスコープ時 (5.2.2.2)✅ (そのまま継承)
継承state必須 - 非openidスコープ時 (5.2.2.3)✅ (そのまま継承)
置換クライアント認証方式5.2.2-4: mTLS/client_secret_jwt/private_key_jwt5.2.2-14: mTLS/private_key_jwt のみ
置換PKCE要件5.2.2-7: S256必須5.2.2-18: PAR時S256必須
固有Request Object必須 (5.2.2-1)-
固有response_type制限 (5.2.2-2)-
固有sender-constrained tokens (5.2.2-5/6)-
固有Request Object exp/nbf/aud (5.2.2-13/15/17)-
固有Public client禁止 (5.2.2-16)-

関連RFC一覧

RFC/仕様正式名称FAPI での役割
RFC 6749The OAuth 2.0 Authorization Framework基盤プロトコル
OIDC Core 1.0OpenID Connect Core 1.0ID Token、UserInfo
RFC 7523JWT Profile for OAuth 2.0 Client Authenticationprivate_key_jwt認証
RFC 7636Proof Key for Code Exchange (PKCE)PKCE S256
RFC 8705OAuth 2.0 Mutual-TLSmTLS認証、Certificate-Bound Token
RFC 9101JWT-Secured Authorization Request (JAR)Request Object
RFC 9126Pushed Authorization Requests (PAR)PAR エンドポイント
RFC 9110HTTP SemanticsBearer トークンヘッダー

🧪 OIDF適合性テスト マッピング

OIDF適合性テストスイート (fapi1-advanced-final-test-plan) の63テストは、各RFCの要件を検証します。

テスト分類サマリー

仕様テスト数主な検証内容
FAPI 1.0 Advanced 5.2.222Request Object、response_type、mTLS、PKCE
FAPI 1.0 Advanced 8.62アルゴリズム制限 (PS256/ES256)
FAPI 1.0 Baseline 5.2.25redirect_uri、nonce
RFC 67497認可コード、scope、state
RFC 75237JWT Client Assertion
RFC 76364PKCE
RFC 87053mTLS
RFC 91268PAR
エッジケース3長いnonce/state
プロファイル固有5UK Open Banking、Brazil等

主要テストと仕様要件の対応

Happy path テスト (#2 fapi1-advanced-final):

  • FAPI 1.0 Advanced 5.2.2-5/6 (sender-constrained tokens)
  • FAPI 1.0 Advanced 5.1 (s_hash, c_hash, at_hash)
  • RFC 8705 Section 3 (Certificate-Bound Access Token)
  • RFC 6749 Section 3.1.2 (redirect_uriクエリ保持)

Request Object 検証テスト (#15-29):

  • 5.2.2-1: 署名必須 → #26, #27, #28, #29
  • 5.2.2-10: RO内パラメータのみ使用 → #10, #17, #18, #19
  • 5.2.2-13: exp-nbf <= 60分 → #15, #21, #23
  • 5.2.2-15: aud検証 → #4, #22, #55
  • 5.2.2-17: nbf 60分以内 → #16, #24

PAR テスト (#47-59):

  • RFC 9126 Section 5: エンドポイント要件 → #53, #54, #57
  • RFC 9126 Section 7.3: request_uri管理 → #47, #48, #49, #52
  • 5.2.2-18: PKCE S256 → #59, #60, #61, #62

詳細なマッピング表は fapi-1.0-advanced-op-test-mapping.md を参照。


🔗 関連ドキュメント

概念・基礎:

実装詳細:

参考実装クラス:

RFC/仕様:


最終更新: 2026-02-17 難易度: ⭐⭐⭐⭐ (上級)