---
title: Dynamic Linking
description: Dynamic linking with PingOne Recognize allows you to display transaction information to the user and sign that information with PingOne Recognize authentication.
component: recognize
page_id: recognize:mobile-sdk:mobile-sdk-dynamic-linking
canonical_url: https://docs.pingidentity.com/recognize/mobile-sdk/mobile-sdk-dynamic-linking.html
llms_txt: https://docs.pingidentity.com/recognize/llms.txt
docs_for_agents: https://developer.pingidentity.com/build-with-ai/docs-for-agents.md
revdate: April 20, 2026
section_ids:
  dynamic-linking-flow: Dynamic Linking Flow
  strong-customer-authentication-sca: Strong Customer Authentication (SCA)
  sca-compliant-dynamic-linking: SCA-Compliant Dynamic Linking
  display-transaction-information: Display Transaction Information
  sca-tied-to-the-authentication-code: SCA Tied to the Authentication Code
  android: Android
  ios: iOS
  flutter: Flutter
  verify-the-transaction: Verify the Transaction
---

# 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](https://eur-lex.europa.eu/legal-content/EN/TXT/?uri=uriserv%3AOJ.L_.2018.069.01.0023.01.ENG\&toc=OJ%3AL%3A2018%3A069%3ATOC) 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

```mermaid
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)](https://keyless.io/solutions/passwordless-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:

```text
[
  {"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:

1. Authenticate the payer with device factor and biometric factor using PingOne Recognize MFA.

2. 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](#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

```kotlin
// {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

```swift
// {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

```dart
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

```text
// 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.
