
FAPI: Open Banking Security Profiles
An examination of FAPI security profiles for open banking, covering JARM, PAR, and conformance requirements for fintech developers.
Open Banking relies on the assumption that third-party providers (TPPs) can access bank data without exposing user credentials. In practice, the base OAuth 2.0 specification is insufficient for this trust model. It allows for several attack vectors, including authorization code interception, cross-site request forgery (CSRF), and URI manipulation.
FAPI (Financial-grade API) solves these problems not by adding new protocols, but by strictly enforcing existing ones. For fintech developers, understanding FAPI means understanding three core mechanisms: JWT Secured Authorization Response Mode (JARM), Pushed Authorization Requests (PAR), and Mutual TLS (mTLS).
The Vulnerability of Standard OAuth 2.0
Consider a standard OpenID Connect (OIDC) authorization code flow. The authorization server redirects the user’s browser back to the client application with an authorization code in the URL fragment or query string:
https://client.example.com/callback?code=SplxlOBeZQQYbYS6WxSbIA&state=xyz
This creates two immediate risks:
- Code Interception: If the code appears in browser history, proxy logs, or Referer headers, an attacker can steal it and use it to exchange for an access token.
- CSRF: An attacker can trick the user into initiating an authorization request they didn’t intend, potentially capturing the code.
FAPI profiles eliminate these risks by changing how the authorization response is delivered and how the initial request is constructed.
JARM: Encrypting the Authorization Response
The first line of defense in FAPI is JARM (JWT Secured Authorization Response Mode), defined by the OpenID Foundation as part of the FAPI specification suite. Instead of returning the authorization code in plain text, the authorization server returns a signed and optionally encrypted JSON Web Token (JWT).
Mechanism
When the client initiates the request, it includes response_mode=jwt in the query parameters. This is a critical component of open banking security, ensuring that the response payload is protected. The authorization server then:
- Constructs a JWT containing the authorization code, state, and issuer information.
- Signs the JWT using its own private key, which the client can verify via the authorization server’s JWKS.
- Returns the JWT in the
responseparameter of the redirect, encoded as a JWT.
Example redirect:
https://client.example.com/callback?response=eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...&state=xyz
Why It Matters
JARM's primary security guarantee is integrity via signing, which ensures that the authorization response has not been tampered with. If the token is modified, the signature check fails. Encryption is an additional layer required by specific FAPI profiles (such as FAPI 2.0 Advanced Profile) and is not inherent to JARM itself. When encryption is applied, the JWT is encrypted using the client’s public key, ensuring only the intended client can decrypt it. This prevents code leakage in logs and browser history while maintaining strict data integrity.
PAR: Pushed Authorization Requests
PAR, defined in RFC 9126, addresses the second major vulnerability: URI manipulation and logging exposure during the initial authorization request.
The Problem
In standard OAuth 2.0, all parameters (client ID, redirect URI, scopes, etc.) are passed in the query string of the authorization request. This exposes sensitive data in server logs, proxy logs, and browser history. It also allows attackers to manipulate parameters via CSRF or URI injection.
The Solution
PAR moves the authorization parameters out of the URL and into a POST request. The flow changes as follows:
- Client POSTs: The client sends a POST request to the authorization server’s
/pushed_authorization_requestendpoint with all parameters in the body. - Server Returns URI: The server validates the request, stores the parameters, and returns a
request_uriand an expiration time (expires_in). - Client Redirects: The client redirects the user to the authorization endpoint, passing only the
request_uri.
Example POST request:
POST /pushed_authorization_request HTTP/1.1
Host: authorization-server.example.com
Content-Type: application/x-www-form-urlencoded
client_id=CLIENT_ID&redirect_uri=https://client.example.com/callback&scope=openid+profile+account&response_type=codeResponse:
{
"request_uri": "urn:ietf:params:oauth:request_uri:abc123",
"expires_in": 60
}Security Implications
By using a request_uri, the actual parameters never appear in the URL. The authorization server validates the request_uri against the stored parameters. If an attacker tries to modify the URI in the redirect, the server will reject it because the URI no longer matches the stored request. This effectively eliminates CSRF and URI manipulation attacks.
Mutual TLS (mTLS) and Conformance
FAPI requires mutual TLS (mTLS) for client authentication. This means the client must present a certificate during the TLS handshake, proving its identity to the authorization server.
Mechanism
- Certificate Registration: The client registers its public certificate with the authorization server.
- Handshake: During the TLS handshake, the client presents its certificate.
- Validation: The server verifies the certificate against its registered list.
This ensures that only authorized clients can initiate authorization requests or exchange tokens. It prevents unauthorized parties from impersonating the client application.
Conformance Requirements
FAPI is not just a set of recommendations; it is a conformance profile. The OpenID Foundation maintains a certification program where implementations must pass a suite of tests to be certified as FAPI-compliant.
For fintech developers, this means:
- Interoperability: Certified implementations are designed to interoperate according to the FAPI specification.
- Security Assurance: Certification ensures that the implementation has been tested against known attack vectors.
- Regulatory Compliance: Many open banking regulations (e.g., PSD2 in Europe) require FAPI-compliant implementations.
Conclusion
FAPI transforms OAuth 2.0 from a flexible but vulnerable protocol into a secure, standardized framework for open banking. By enforcing JARM, PAR, and mTLS, it eliminates the most common attack vectors in financial APIs. For developers, this means stricter requirements but significantly higher security. Understanding these mechanisms is not optional; it is essential for building secure, compliant fintech applications.
Implementing FAPI requires careful attention to detail. Developers must ensure their clients support JARM, integrate with PAR endpoints, and handle mTLS certificates correctly. Failure to do so can result in security vulnerabilities or non-compliance with regulatory requirements.
The future of open banking depends on trust. FAPI provides the technical foundation for that trust, ensuring that data flows securely between banks and third-party providers. By implementing JARM, PAR, and mTLS, developers can build applications that are not only functional but also secure and compliant.
FAQ
Is JARM encryption mandatory for all FAPI profiles? No. JARM signing is mandatory to ensure integrity. Encryption is required only for the FAPI 2.0 Advanced Profile, which demands higher levels of confidentiality for the authorization response.
Can I use PAR with standard OAuth 2.0 clients? PAR is an extension defined in RFC 9126. Standard OAuth 2.0 clients that do not implement PAR cannot use this feature. Both the client and the authorization server must support the PAR extension to utilize pushed authorization requests.
How does mTLS differ from client certificate authentication? In FAPI, mTLS is used for binding the client certificate to the authorization request and token exchange. This ensures that the entity presenting the certificate is the same entity that initiated the request, preventing token theft if the authorization code is intercepted.
What happens if a PAR request expires before the user authenticates?
If the request_uri expires, the authorization server will reject the subsequent redirect. The client must then initiate a new PAR request to obtain a fresh request_uri before redirecting the user again.
Pitfalls
- Ignoring JARM Encryption Requirements: Assuming that signing alone is sufficient for all profiles. Developers must check if the specific FAPI profile (e.g., Advanced) mandates encryption and configure their JWKS and encryption keys accordingly.
- Incorrect PAR Expiration Handling: Failing to handle
expires_incorrectly can lead to user experience issues or security rejections. Clients must be robust enough to retry PAR requests if the initial one expires during slow user interaction. - mTLS Certificate Mismatch: Registering the wrong certificate or failing to update certificates before expiration can break the mTLS handshake. Automated certificate rotation and monitoring are essential for maintaining continuous compliance.
Related posts
RFC 9126: Pushed Authorization Requests
An examination of RFC 9126 Pushed Authorization Requests (PAR) for OAuth 2.0, detailing how request_uri enhances security and performance for backend developers.
Implementing PSD2 SCA: Cryptographic Intent Binding
An examination of PSD2 Strong Customer Authentication (SCA) requirements, dynamic linking, and exemptions for fintech developers and compliance engineers.
Implementing Identity Verification for KYC
A technical guide to implementing identity verification for Know Your Customer compliance using document verification and biometrics in fintech.