App2App is a financial-grade design pattern where a mobile app can authenticate users via a separate high-security mobile app. This provides an out-of-the-box Strong Customer Authentication (SCA) solution.
In this article, we will describe the App2App flow, then dive deeper into Open Banking solutions, where merchant apps can use App2App to login via a bank app.
The App2App flow is illustrated below, showing that the mobile app simply needs to open a browser at the identity server’s authorization endpoint. This requires login, which the authorization server handles by redirecting the browser to a URL registered on the mobile device. This URL is handled by a login application installed on the same device.
As a result, the login app is presented to the user, and the user signs in. The login app then invokes a URL that is again handled by the browser, which completes the authorization request by redirecting to the client app’s redirect URI. This brings up the app with the authorization code, representing the end user’s authorization. The app exchanges this for an access token, using PKCE to protect against redirect interception. The resulting token can then be used to call APIs.
The following technical steps are performed to sign the user in, manage browser redirects securely, then get tokens with which to call APIs:
|1. App Opens System Browser||Before starting authentication, the client app presents a system browser, which will handle HTML responses|
|2. Authorization Request Sent||The client app creates an OpenID Connect authentication request and sets the browser URL to trigger a login redirect|
|3. Redirect Response Received||The client app receives a redirect response from the authorization server, containing a deep link URL to the login app|
|4. Login Redirect Followed||The browser follows the login redirect, which lands on a page from which the user is deep linked to the login app|
|5. User Authenticates||The end-user signs in via the login app, using multi-factor authentication|
|6. Login Completes||The login app posts the login result to the authorization server (directly or indirectly)|
|7. Polling Completes||During login, the system browser page in the client app polls the authorization server for a login result|
|8. Authorization Code Returned||A login result is returned to the system browser containing an authorization code to complete the sign-in process, after which the browser is closed|
|9. Access Token is Retrieved||The mobile app then swaps the authorization code for OAuth tokens|
|10. Access Token is Used||The mobile app then uses the access token as a message credential when calling APIs|
Although the above picture has quite a few moving parts, the client app only needs to implement the AppAuth Pattern described in RFC8252. This can be done relatively easily by integrating the open-source libraries:
|AppAuth for iOS||Invokes a Chrome Custom Tab browser window on which to perform logins, then handles all OAuth messages|
|AppAuth for Android||Invokes an ASWebAuthenticationSession window on which to perform logins, then handles all OAuth messages|
The Login App implements OpenID Connect via a Claimed HTTPS Scheme, which means an HTTPS URL is used for deep linking, using mobile platform features:
Claimed HTTPS schemes prevent malicious mobile apps on user devices from registering the same URL and intercepting login responses. In this way, the scheme, combined with the mobile operating system’s key verification, establishes the provenance of the application. It also enables the following two scenarios to be handled gracefully for end-users:
|User Scenario||Login Behavior|
|Login app is not installed||The client app’s browser renders a public web page to prompt the user to download and install the app|
|Login app is already installed||The client app’s browser invokes the deep link URL to start the login app on the same device|
Some companies offer specialist apps to manage the mechanics of Multi-Factor Authentication (MFA). An example provider is BankID, which multiple banks can use as part of their mobile banking solutions.
In an Open Banking scenario, a merchant app can quickly meet its PSD2 Strong Customer Authentication (SCA) requirement by implementing App2App via a bank app. However, any real-world solution is likely to include merchant APIs, so the merchant will also need to protect their own data. In this case, the problem with the App2App flow is that bank access tokens are not designed to secure merchant APIs.
In the final step above, the merchant API receives an access token issued by the bank, and has little or no control over the following aspects:
|Token Validation||It may not be possible to get keys needed to validate the received access token|
|User Identification||It may not be possible to identify or match up users based on the token’s subject claim|
|Scopes and Claims||It will not be possible for the merchant to provide its own scopes and claims to its APIs|
|Lifetimes||The merchant will not be able to control lifetimes for access tokens or the mobile app’s user session|
|Future Changes||The merchant APIs may break when the bank applies future unknown changes|
The standard solution to these problems is for both the merchant and the bank to use an authorization server.
The following sections will illustrate how the App2App flow changes when a merchant introduces an authorization server. A key point to understand is that this only requires security configuration changes — zero code changes are needed in the merchant’s mobile app.
The flow during authentication now involves the Merchant Authorization Server calling the Bank Authorization Server to get the redirect URL to the bank login app:
There are also two different authorization codes issued, once login completes, which are also handled via browser redirects:
When the app swaps code for tokens, the Merchant Authorization Server exchanges the bank authorization code for tokens at the Bank Authorization Server.
The Merchant Authorization Server then receives a Bank Access Token but also issues Merchant Access Tokens with whatever scopes and claims the merchant’s APIs require.
The bank token may then be embedded in the merchant token so that both are stored in the authorization server state. An opaque reference token is then returned to the Merchant Mobile App:
For further details on these token issuing patterns, and how merchant APIs would use scopes and claims, see the below articles:
Finally, the merchant mobile app can initiate calls to both its own APIs and also to the bank’s API. The merchant APIs can implement authorization using scopes and claims from access tokens.
Calls to bank APIs typically need to be routed via the merchant’s API so that Mutual TLS can be used. During this downstream call, the merchant API forwards the bank token contained in the composite token.
App2App options can also be selected at runtime, since a key goal of Open Banking is to connect the following parties dynamically:
|Bank||A bank acts as an ‘Account Servicing Payment Service Provider’ (ASPSP) and provides App2App solutions for multiple merchant apps|
|Merchant||A merchant acts as a ‘Third Party Provider’ (TPP) and provides apps that integrate with multiple banks on behalf of consumers|
|Consumer||A consumer acts as a ‘Payment Service User’ (PSU) and can use one or more bank accounts within the same or different merchant apps|
Typically a merchant app will present a screen to sign in via one or more of the main banks. Each consumer will select a bank to sign in with and will then need to use that bank’s App2App flow. This sign-in process could be repeated multiple times for different banks.
The merchant app can use the Authentication Context Class Reference (acr) Claim, or the
acr_values query parameter, to tell its authorization server which bank to use for the App2App login and to deep link straight to that bank’s app. After login, the app will also receive the acr claim in its id token.
In some cases, such as if the user cannot authenticate with the bank, the merchant may provide a fallback authentication option with the following type of behavior:
|Authentication Level||User Privileges|
|Standard Authentication||The user has basic privileges such as viewing their transaction history|
|Strong Customer Authentication||The user can perform high privilege operations such as payments|
To enforce these rules during API authorization, the merchant can dynamically add a claim such as
authentication_level to access tokens based on the runtime authentication method(s) used.
Adding this claim requires a capability to process the authentication context and apply custom logic during token issuance. In the Curity Identity Server this is possible using a Custom Claims Value Provider, which can inspect the authentication context and issue custom claims.
In some ways, the AppAuth pattern is a little unnatural when logging on via a deep link to an external mobile app, since the user sees the system browser popup and then disappear, but the browser does not render anything:
With the Curity Identity Server, an alternative approach is to bypass the browser and use the Hypermedia Authentication API (HAAPI), which has usability, security, and deployment benefits.
The App2App via Hypermedia Authentication API tutorial shows how to get App2App working with the Curity Identity Server. This is done via a small mobile code sample that signs the user in via a deep link to the BankID app.
By implementing the OpenID Connect App2App flow, Strong Customer Authentication (SCA) requirements can be met via an out-of-the-box solution, where all of the security complexity is outsourced.
For Open Banking solutions, merchants also need to protect their own data, and should use a federated form of App2App. With the correct design choices, a full end-to-end solution requires only simple code.