Dynamic Linking
You can use the PingOne Recognize authentication mechanism to sign unrelated transactions, including Strong Customer Authentication (SCA) transactions.
Payment service providers compliant with SCA PSD2 dynamic linking are required to:
-
Generate an authentication code specific to the amount of the payment transaction and the payee agreed to by the payer when initiating the transaction.
-
Make the payer aware of the amount of the payment transaction and of the payee.
PingOne Recognize helps by:
-
Protecting the authentication code used for dynamic linking.
-
Displaying and signing information to make the payer aware of transaction details.
| PingOne Recognize is not a payment service provider. PingOne Recognize does not issue an authentication code tied to transaction information. |
Dynamic Linking Flow
sequenceDiagram
participant Customer backend
participant Customer app
participant {p1recognize} SDK
participant {p1recognize} API
Customer app->>{p1recognize} SDK: Keyless.Authenticate(transaction details)
{p1recognize} SDK->>{p1recognize} SDK: User reviews transaction details<br/>and approves transaction
note over {p1recognize} SDK,{p1recognize} API: {p1recognize} authentication happens<br/>{p1recognize} signs transaction details
{p1recognize} SDK->>Customer app: KeylessResult includes<br/>a signed JWT with transaction details
Customer app->>Customer backend: Customer app sends<br/>signed JWT to backend
Customer backend->>Customer backend: Backend validates signature
Strong Customer Authentication (SCA)
By adding PingOne Recognize to your checkout flow, you also benefit from PingOne Recognize Passwordless Multi-Factor Authentication (MFA).
SCA requires authentication to use at least two of the following three elements:
-
Something the customer knows (for example, password or PIN)
-
Something the customer has (for example, mobile phone or hardware token)
-
Something the customer is (for example, biometric such as fingerprint or face)
With PingOne Recognize Passwordless MFA, you can satisfy the last two points in the list above.
SCA-Compliant Dynamic Linking
The following sections show examples of implementing SCA with PingOne Recognize.
Display Transaction Information
PingOne Recognize displays a screen containing labels and associated information on your behalf.
For this reason, dynamicLinkingInfo must be a JSON array containing JSON objects (key/value pairs). Expected format:
[
{"key1": "value1"},
{"key2": "value2"},
...,
{"keyN": "valueN"}
]
This information is added to the authentication request the user must approve.
SCA Tied to the Authentication Code
After the user approves transaction data, PingOne Recognize starts authentication to:
-
Authenticate the payer with device factor and biometric factor using PingOne Recognize MFA.
-
Tie transaction data to PingOne Recognize MFA.
To tie transaction data to PingOne Recognize MFA, populate dynamicLinkingInfo in AuthConfig.
Add the authentication code or other information you want to display to the user and sign with PingOne Recognize MFA.
The transactionData in dynamicLinkingInfo must follow the format described in Display Transaction Information.
|
PingOne Recognize can produce a signed JWT containing a claim titled td (transaction data), which contains the payload passed as dynamicLinkingInfo.
| PingOne Recognize does not store transaction history records for amount, payee, payer, or authentication code. |
Android
// {p1recognize} adds a td claim to JWT containing the data you specify
val dynamicLinkingInfo = DynamicLinkingInfo(transactionData = "<your transaction data to display and sign>")
// Authenticate with biometric
val biomAuthConfig = BiomAuthConfig(dynamicLinkingInfo = dynamicLinkingInfo)
// Perform authentication
Keyless.authenticate(
configuration = biomAuthConfig,
onCompletion = { /* TODO: process result */ }
)
iOS
// {p1recognize} adds a td claim to JWT containing the data you specify
let dynamicLinkingInfo = DynamicLinkingInfo(transactionData = "<your transaction data to display and sign>")
// Authenticate with biometric
let biomAuthConfig = BiomAuthConfig(dynamicLinkingInfo: dynamicLinkingInfo)
// Perform authentication
Keyless.authenticate(
configuration: biomAuthConfig,
onCompletion: { /* TODO: process result */ }
)
Flutter
import 'package:keyless_flutter_sdk/keyless.dart';
import 'package:keyless_flutter_sdk/models/configurations/authentication_configuration.dart';
import 'package:keyless_flutter_sdk/models/dynamic_linking_info.dart';
final dynamicLinkingInfo = DynamicLinkingInfo(
transactionData: "<your transaction data to display and sign>",
);
// Authenticate with biometric
final biomAuthConfig = BiomAuthConfig(dynamicLinkingInfo: dynamicLinkingInfo);
try {
// Perform authentication
final result = await Keyless.instance.authenticate(biomAuthConfig);
// Process signed JWT from result.signedJwt
print("Authentication successful. Signed JWT: ${result.signedJwt}");
} catch (error) {
print("Authentication failed: $error");
}
Verify the Transaction
If authentication succeeds, AuthenticationSuccess includes:
-
signedJwt: the signed JWT
// JWT header
{
"alg": "ES256",
"typ": "JWT",
"kid": "PIN/FACE"
}
// JWT payload
{
"iat": 1720519812,
"td": "your transaction data to display and sign",
"version": "1.1.0",
"sub": "keyless_id",
"external_user_id": "external user id only if present"
}
The external_user_id claim is included only if the user requesting the JWT has an associated external user ID.
|
Verify the JWT using the public key from PingOne Recognize backend operations API.
You have now performed a Strong Customer Authentication flow that displays and signs transaction information.