> For the complete documentation index, see [llms.txt](https://docs.payments.thalescloud.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.payments.thalescloud.io/push-provisioning/implement-push-provisioning/implement-view-and-control/in-app-authentication.md).

# In app authentication

{% hint style="danger" %}
Tokenization service is required to use Thales D1 SDK for "in-app authentication" flow.
{% endhint %}

When tokenizing a card in a digital wallet, manually or from the issuer application, it is possible that a step up end user authentication is required.

Among the different ID\&V options offered by the issuer to the end user, the in-app authentication scenario relies on the issuer application to verify the end user identity.

It is possible to use D1 SDK to activate the digital card after a successful authentication.

The issuer app **must**, first, integrate properly with the wallet provider and recognize, from the Wallet call, the card for which the authentication is required.

This is described in details for each platform in the [Integrate in-app ID\&V for xPay Wallets](/push-provisioning/integrate-in-app-id-and-v-for-xpay-wallets.md) section.

## In-App Authentication Flow

**Pre-requisites**

* End user, account and card were registered in D1
* SDK is properly initialized

<figure><img src="/files/41TJMPhYNwSyMQNbIDVu" alt=""><figcaption></figcaption></figure>

{% stepper %}
{% step %}

#### Identify the card

Identify the card for which the authentication is required (described in [Integrate in-app ID\&V for xPay Wallets](/push-provisioning/integrate-in-app-id-and-v-for-xpay-wallets.md)).
{% endstep %}

{% step %}

#### Authenticate the end user

Authenticate the end user and generate an `accessToken` as defined in the [login flow to D1 SDK](/push-provisioning/integrate-the-d1-sdk/getting-started/configuration/5.-authentication/sdk-login.md) to authorise the card activation.
{% endstep %}

{% step %}

#### Activate the card with D1 SDK

Call the D1 SDK API `activateDigitalCard` with `digitalCardID` ([Android](https://thalesgroup.github.io/d1sdk-docs/d1-sdk/latest/android/com/thalesgroup/gemalto/d1/card/D1PushWallet.html#activateDigitalCard\(java.lang.String,com.thalesgroup.gemalto.d1.D1Task.Callback\))/[iOS](https://thalesgroup.github.io/d1sdk-docs/d1-sdk/4.3.0/ios/documentation/d1/d1task/activatedigitalcard\(withdigitalcardid:completion:\))) to activate the card.
{% endstep %}
{% endstepper %}

Since D1 SDK V3.2.0, D1 SDK provides new API to activate the digital card. Platform-specific examples:

{% tabs %}
{% tab title="Android" %}

```kotlin
//digitalCardID: Parsed from EXTRA_TEXT coming from the wallet app.
fun activeDigitalCard(d1Task: D1Task, digitalCardID: String) {
    //Call D1PushWallet.activateDigitalCard to activate the card.
    d1Task.d1PushWallet.activateDigitalCard(
        digitalCardID,
        object : D1Task.Callback<Void?> {
            override fun onSuccess(data: Void?) {
                Log.w(TAG, "Card Activation - DONE")
                //Shows the activation result to the user.
                //On user acknowledgement redirect user back to Google wallet.
            }

            override fun onError(exception: D1Exception) {
                //Shows the activation result to the user.
            }
        }
    )
}
```

{% endtab %}

{% tab title="iOS" %}

```swift
let digitalCardID = ""  // obtained from PKPass
d1Task.activateDigitalCard(withDigitalCardID: digitalCardID) { error in
    if let error = error {
        // Handle error
    } else {
        // Proceed with subsequent flows. For example, update UI.
    }
}
```

{% endtab %}
{% endtabs %}

{% hint style="info" %}
The `deviceAccountIdentifier` corresponds to the `digitalCardId` in D1 and this ID can be used to activate the digital card.

`primaryAccountNumberSuffix` is the last four digits of the PAN that has been tokenized. This can be used to recover the card art and display it to the end user for the authentication request.
{% endhint %}

### Apple Pay

Since D1 SDK V3.2.0, D1 SDK has provided a [digitalCardPass](https://thalesgroup.github.io/d1sdk-docs/d1-sdk/4.3.0/ios/documentation/d1/d1task/digitalcardpass\(forserialnumber:\)) API for the integrator to obtain the digital card passes based on the respective serial numbers.

```swift
func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
    guard let components = URLComponents(url: url, resolvingAgainstBaseURL: true) else {
        // handle error e.g. logging
        return false
    }
    
    guard let queryItems = components.queryItems else {
        // handle error e.g. logging
        return false
    }

    // example of checking the query items
    let containsPassTypeIdentifier = queryItems.contains(where: { $0.name == "passTypeIdentifier" && $0.value == "paymentpass.com.apple" })
    let indexSerialNumber = queryItems.firstIndex(where: { $0.name == "serialNumber" })
    let containsAction = queryItems.contains(where: { $0.name == "action" })
    let validated = containsPassTypeIdentifier && indexSerialNumber != nil && containsAction

    guard validated, let indexSerialNumber = indexSerialNumber else {
        // handle error e.g. show error UI
        return false
    }

    guard let serialNumber = queryItems[indexSerialNumber].value else {
        // handle error e.g. show error UI
        return false
    }

    do {
        guard let pkPass = try d1Task.digitalCardPass(forSerialNumber: serialNumber) else {
            // handle error e.g. show error UI
            return false
        }

        guard let deviceAccountIdentifier = pkPass.secureElementPass?.deviceAccountIdentifier,
              let primaryAccountNumberSuffix = pkPass.secureElementPass?.primaryAccountNumberSuffix else {
            // handle error e.g. show error UI
            return false
        }

        // show primaryAccountNumberSuffix for confirmation UI

        // continue with card activation
        let digitalCardID = deviceAccountIdentifier
        d1Task.activateDigitalCard(withDigitalCardID: digitalCardID) { error in
            if let error = error {
                // handle error e.g. show error UI
            } else {
                // show activation result to the user.
            }
        }

        return true
    } catch {
        // handle error e.g. show error UI
        return false
    }
}
```

### Google & Samsung Pay

To complete the activation, the issuer app must start an activity context to complete the token activation using the activation parameters passed in the `Intent`.

```kotlin
/*
 * Within issuer's mobile app AppToAppActivity (CardActivationActivity)
 * extra library: com.fasterxml.jackson.core:jackson-core & com.fasterxml.jackson.core:jackson-databind
 * import android.util.Base64;
 * import com.fasterxml.jackson.databind.JsonNode;
 * import com.fasterxml.jackson.databind.ObjectMapper;
 */
fun activeDigitalCard_inAppAuthentication(d1Task: D1Task, activity: Activity) {
    /*
     * After receiving the intent, the application must use the Activity.getCallingPackage() API to
     * validate that the request is coming from Google Pay or Samsung Pay as follows:
     */
    // Validates if the caller is Google Wallet (Google Play Services) or Samsung Pay
    if ("com.google.android.gms".equals(getCallingPackage()) ||
        "com.samsung.android.spay".equals(getCallingPackage())) {
        // Proceeds with token activation.
    } else {
        // Aborts token activation: handle error.
    }

    val data: String? = activity.getIntent().getStringExtra(Intent.EXTRA_TEXT)
    if (data == null){
        // Abort token activation: handle error
    }

    try {
        // Parses base64 to retrieve the activation parameters as a JSON object in a String.
        val decodedDataBytes = Base64.decode(data, Base64.DEFAULT)
        val decodedData = String(decodedDataBytes, StandardCharsets.UTF_8)

        // Reads the JSON string using Jackson.
        val mapper = ObjectMapper()
        val node = mapper.readTree(decodedData)

        var digitalCardId: String = ""
        var scheme = CardScheme.VISA.scheme
        var panLast4: String = ""
        var tokenRequestorId: String = ""

        if (node["tokenReferenceID"] != null) { // VISA Scheme
            // For VISA -> tokenReferenceID : digitalCardId.
            digitalCardId = node["tokenReferenceID"].asText() // VISA
            panLast4 = node["panLast4"].asText() // VISA

            // tokenRequestorId -> "40010075001" for Google Pay or "40010043095" for Samsung Pay.
            // This is relevant only in case SCHEME is VISA. For MASTERCARD put empty string.
            tokenRequestorId = node["tokenRequestorID"].asText() // VISA

        } else { // MASTERCARD
            // For MasterCard -> tokenUniqueReference : D1 -> digitalCardId.
            digitalCardId = node["tokenUniqueReference"].asText() // MasterCard
            panLast4 = node["accountPanSuffix"].asText() // MasterCard
            scheme = CardScheme.MASTERCARD.scheme
        }

        // Note: Application must show panLast4 as Card Identification.

        // Login before activate digital card.

        // Call D1PushWallet.activateDigitalCard to activate the card.
        d1Task.d1PushWallet.activateDigitalCard(
            digitalCardId,
            object : D1Task.Callback<Void?> {
                override fun onSuccess(data: Void?) {
                    Log.w(TAG, "Card Activation - DONE");
                    // Shows the activation result to the user.
                    // On user acknowledgement redirect user back to Google wallet.
                    sendResultToWalletApp(activity, null)
                }

                override fun onError(exception: D1Exception) {
                    // Shows the activation result to the user.
                    sendResultToWalletApp(activity, exception)
                }
            }
        )
    } catch (exception: IOException) {
        // Aborts token activation: handle error.
    }
}

private fun sendResultToWalletApp(activity: Activity, exception: D1Exception?) {
    val resultIntent = Intent()
    // "approved", or "failure"
    resultIntent.putExtra("BANKING_APP_ACTIVATION_RESPONSE",if (exception == null) "approved" else "failure")

    activity.setResult(Activity.RESULT_OK, resultIntent)
    activity.finish()
}
```

#### Google Pay Wallet State Update

It is recommended that the issuer application registers for Google Pay wallet state changes so that it can update the latest status of the wallet/card on the UI.

These changes include:

* When the active wallet changes (by changing the active account).
* When the selected card of the active wallet changes.
* When tokenized cards are added or removed from the active wallet.
* When the status of a token in the active wallet changes.

```kotlin
fun updateGooglePayWalletState(d1Task: D1Task) {
    // Register callback should be done as early as possible, for example right after d1Task.configure() success.
    d1Task.registerCardDataChangedListener {
        // Refresh card status/info here.
    }

    // UnRegister callback should happen when the end user exits the app
    d1Task.unRegisterCardDataChangedListener()
}
```

{% hint style="info" %}
Only foreground applications will be notified of the data change events. Therefore, each application should update the token statuses not only by receiving updates from the callback but also when the application launches or returns to the foreground.
{% endhint %}

For a full access to the D1 SDK, please check [API reference](/push-provisioning/integrate-the-d1-sdk/api-reference.md).


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.payments.thalescloud.io/push-provisioning/implement-push-provisioning/implement-view-and-control/in-app-authentication.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
