← Payment Reference GuidesAPI Security Reference
FAPI: the Financial-grade API Security Profiles
FAPI is the OpenID Foundation's hardened profile of OAuth 2.0 and OpenID Connect for APIs where a stolen token means a stolen payment. This guide covers FAPI 1.0 Baseline and Advanced, the FAPI 2.0 Security Profile and its attacker model, Message Signing and CIBA — what each one requires, the authorization-code flow message by message, which open-banking ecosystems mandate which profile, and a checklist for shipping it.
The building blocks
FAPI 2.0 invents almost nothing. It is a fixed selection of IETF and OpenID specifications, each doing one job:
| Spec | Name | Job in FAPI 2.0 |
|---|---|---|
| RFC 6749 / 6750 | OAuth 2.0 and Bearer Token Usage | The authorization code grant; tokens in the Authorization header, never in a query string. |
| RFC 9126 | Pushed Authorization Requests (PAR) | All authorization parameters go server-to-server with client authentication; the browser carries only client_id and a short-lived request_uri. |
| RFC 7636 | PKCE | S256 challenge, fresh per request and bound to the user agent — the CSRF and code-injection defence. |
| RFC 9207 | Issuer Identification | iss in the authorization response; the client checks it against the metadata issuer to stop mix-up attacks (A1a). |
| RFC 8705 | OAuth mTLS | Client authentication by certificate and certificate-bound access tokens (cnf.x5t#S256); mtls_endpoint_aliases for mixed deployments. |
| RFC 9449 | DPoP | Application-layer proof of possession: a per-request JWT signed with the client's key, access tokens bound to cnf.jkt, server nonces, code binding via dpop_jkt. |
| OIDC Core §9 | private_key_jwt | Client authentication with a signed assertion whose aud is the issuer identifier (as a string, not an array). |
| RFC 8414 / OIDC Discovery | Authorization Server Metadata | The only permitted source of endpoint URLs; the client verifies issuer matches the URL it fetched from. |
| RFC 9700 (BCP 240) | OAuth 2.0 Security Best Current Practice | The threat catalogue FAPI 2.0 follows: no open redirectors, no 307 redirects with credentials, one-time codes. |
| RFC 8725 | JWT Best Current Practices | How every JWT (assertions, DPoP proofs, request objects, ID tokens) is created and validated. |
| BCP 195 · RFC 9525 | TLS recommendations · certificate verification | TLS 1.2 minimum, recommended cipher suites only on server-to-server endpoints, hostname verification. |
| RFC 9396 | Rich Authorization Requests (recommended) | authorization_details when scope cannot express "pay €120.00 to IBAN … once". |
| RFC 9101 · JARM · RFC 9701 | JAR · JWT Secured Authorization Response · JWT introspection responses | Only with Message Signing: non-repudiable requests, responses and introspection results. |
What the authorization server shall do
Paraphrased from the Security Profile's "requirements for authorization servers" (general and authorization-endpoint lists). Shall is normative.
Clients, grants, tokens
- Publish discovery metadata (RFC 8414 / OIDC Discovery).
- Reject the resource-owner password grant; support only confidential clients.
- Issue only sender-constrained access tokens, bound by mTLS (RFC 8705) or DPoP (RFC 9449).
- Authenticate clients only by mTLS or private_key_jwt; accept the issuer identifier only as a string in the assertion's aud.
- No refresh-token rotation except in extraordinary circumstances (migration), and then with a time-limited retry on the old token.
- If DPoP: support authorization-code binding to the DPoP key (dpop_jkt); may use server-provided nonces.
- Accept JWTs with iat/nbf up to 10 s in the future; reject beyond 60 s.
- No open redirectors. Least-privilege tokens (should).
Authorization endpoint
- response_type must be code.
- Support client-authenticated PAR; reject authorization requests that did not come through PAR; reject unauthenticated PAR.
- Require PKCE with S256; require redirect_uri in the PAR request.
- Return iss in the authorization response (RFC 9207).
- No http redirect URIs except loopback for native apps (RFC 8252); reject a previously used code.
- Never redirect with HTTP 307 when the request carries credentials; 303 is recommended.
- request_uriexpires_in under 600 s; enforce one-time use at authorization time, not page load.
- Support OIDC nonce values up to 64 characters (if OIDC is offered).
- Show the user who the client is and what it asks for (should).
Clients (TPP / relying party)
- Support mTLS and/or DPoP token binding, and mTLS and/or private_key_jwt client authentication.
- Use PAR for every authorization request; send only client_id and request_uri to the authorization endpoint.
- Fresh PKCE challenge per request, bound to the client and the user agent that started the flow.
- Check iss in the response against the metadata issuer.
- Take endpoint URLs only from metadata fetched from an authoritative issuer URL over a secure channel; verify the issuer value matches.
- Support refresh tokens (and rotation, should the server ever do it); support mtls_endpoint_aliases; support DPoP server nonces.
- Only start a flow with the user's explicit or implicit consent, protected against CSRF.
Resource servers (the API)
- Accept access tokens only in the Authorization header (Bearer or DPoP scheme); never in query parameters.
- Verify validity, integrity, expiry and revocation status of every token.
- Check that the token's authorization covers the requested resource; otherwise fail per RFC 6750 §3.1.
- Verify the sender constraint: the presented client certificate matches cnf.x5t#S256, or the DPoP proof matches cnf.jkt (with ath, method and URI).
Cryptography and transport
| Area | Requirement |
|---|---|
| JWS algorithms | PS256, ES256 or EdDSA (Ed25519). Never none; RS256 and HS256 are out. Follow RFC 8725. |
| Key sizes | RSA ≥ 2048 bits; elliptic-curve ≥ 224 bits. |
| Secrets not handled by users | Access tokens, refresh tokens, codes: at least 128 bits of entropy. |
| JWKS | Serve jwks_uri over TLS only; avoid x5u / jku headers; avoid duplicate kids — and when they occur, verifiers pick the key by alg, use, kty, crv. |
| TLS, all endpoints | TLS 1.2 or later, BCP 195, server certificate check per RFC 9525; DNSSEC should be used. |
| TLS, server-to-server | With TLS 1.2 only the IANA recommended cipher suites; MTLS ecosystems should publish their CA trust list. |
| TLS, browser-facing | No TLS-stripping downgrades (preloaded HSTS); any BCP 195-allowed suite; no CORS on the authorization endpoint. |
The numbers to remember
≤ 60 sauthorization code lifetime
< 600 sPAR request_uri expiry
10 s / 60 sfuture iat/nbf: must accept / must reject
≤ 60 minsigned request object nbf age and exp span (Message Signing)
64 charsOIDC nonce servers must support
2048 / 224minimum RSA / EC key bits
128 bitsentropy of tokens and codes
12 monthsto adopt a new BCP 195 / cipher-suite registry revision
Compact version: FAPI cheatsheet on the standards page →
Next steps
ToolBase64 Encoder / DecoderEncode and decode Base64 and Base64URL (RFC 4648) — text or hex bytes, padding and MIME/PEM line breaks. Useful for API payloads, certificate data and token inspection.Open the tool ToolASN.1 / DER DecoderDecode ASN.1 DER and BER (including indefinite length) from hex, base64 or PEM — useful for certificate and key data in payment systems.Open the tool ToolHMAC & SHA HashesCompute HMAC-SHA256, HMAC-SHA512, SHA-1, SHA-256, and SHA-512 of hex or text input for message integrity checks.Open the tool FlowFAPI 2.0 authorization code and CIBA flowsSee the animated message flow, step by step, between every party involved.Watch the flow
Related articles
Open BankingOpen Banking & PSD2AISP/PISP roles, consent & SCA flows, FAPI security, UK / Berlin Group / STET, PSD3 & PSRRead article IdentityEUDI Wallet & PaymentseIDAS 2.0 deadlines, the SD-JWT VC / mdoc / OID4VP stack, wallet-based PSD2 SCARead article Authentication3D Secure (EMV 3DS)Authentication flows, message types, ECI values, SCA exemptionsRead article AgenticAgentic Payments: AP2, ACP & the Trust StackAP2 mandates, ACP/UCP checkout, Web Bot Auth & Visa TAP, EMVCo Intent Services, x402/MPP or card settlementRead article