> 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/click-to-pay/es/integrate-the-d1-sdk/getting-started/configuration/5.-authentication/sdk-login/iniciar-sesion-en-multiples-usuarios-finales-y-emisores.md).

# Iniciar sesión en múltiples usuarios finales y emisores

The updated login API supports multiple `D1Task` instances and multiple issuer access tokens.

This is useful when one issuer application manages several issuers or several consumer IDs.

Key behaviors:

* Log in once with all relevant issuer access tokens.
* Use any configured `D1Task` instance after login without authenticating again.

{% tabs %}
{% tab title="Android" %}
{% code lineNumbers="true" %}

```java
class D1Task {
  public void login(
            @NonNull final List<byte[]> issuerTokens,
            @NonNull final Callback<Void> callback
    );
}
```

{% endcode %}
{% endtab %}

{% tab title="iOS" %}
{% code overflow="wrap" lineNumbers="true" %}

```swift
class D1Task {
    public func login(_ issuerTokens: inout [Data], completion: @escaping (D1Error?) -> Void)
}
```

{% endcode %}
{% endtab %}
{% endtabs %}

#### Configure multiple `D1Task` instances

Create one `D1Task` instance per issuer and consumer combination.

{% tabs %}
{% tab title="Android Java" %}
{% code lineNumbers="true" %}

```java
// --- Placeholders you already have in your app / DI ---
Activity activity = myActivity;/* your Activity */;
OEMPayType oemPayType = OEMPayType.GOOGLE_PAY;/* e.g., OEMPayType.GOOGLE_PAY or SAMSUNG_PAY */;
String samsungServiceId = "serviceID";/* your Samsung Pay service ID or "" if not used */;
String visaClientAppId = "clientID"; /* your Visa client app ID or "" if not used */;

// --- D1Task declarations ---
D1Task d1Task1 = null; // Uses ISSUER_ID_1 issuerToken with CONSUMER_ID_1
D1Task d1Task2 = null; // Uses ISSUER_ID_1 issuerToken with CONSUMER_ID_2
D1Task d1Task3 = null; // Uses ISSUER_ID_2 issuerToken with CONSUMER_ID_3

// --- Consumer IDs ---
final String consumerID1 = "CONSUMER_ID_1";
final String consumerID2 = "CONSUMER_ID_2";
final String consumerID3 = "CONSUMER_ID_3";

// --- Build common per-task config params ---
D1Params cardCfg1 = ConfigParams.buildConfigCard(activity, oemPayType, samsungServiceId, visaClientAppId);
D1Params cardCfg2 = ConfigParams.buildConfigCard(activity, oemPayType, samsungServiceId, visaClientAppId);
D1Params cardCfg3 = ConfigParams.buildConfigCard(activity, oemPayType, samsungServiceId, visaClientAppId);

// --- Configure d1Task1 ---
D1Params coreCfg1 = ConfigParams.buildConfigCore(consumerID1);
d1Task1.configure(new D1Task.ConfigCallback<Void>() {
    @Override
    public void onSuccess(Void ignore) {
        // configured successfully for consumerID1
    }
    @Override
    public void onError(@NonNull List<D1Exception> exceptions) {
        for (D1Exception ex : exceptions) {
            // Handle errors as per "D1 SDK Integration – Error Management"
            // e.g., log/route by ex.getCode(), ex.getMessage()
        }
    }
}, coreCfg1, cardCfg1);

// --- Configure d1Task2 ---
D1Params coreCfg2 = ConfigParams.buildConfigCore(consumerID2);
d1Task2.configure(new D1Task.ConfigCallback<Void>() {
    @Override
    public void onSuccess(Void ignore) {
        // configured successfully for consumerID2
    }
    @Override
    public void onError(@NonNull List<D1Exception> exceptions) {
        for (D1Exception ex : exceptions) {
            // Handle errors
        }
    }
}, coreCfg2, cardCfg2);

// --- Configure d1Task3 ---
D1Params coreCfg3 = ConfigParams.buildConfigCore(consumerID3);
d1Task3.configure(new D1Task.ConfigCallback<Void>() {
    @Override
    public void onSuccess(Void ignore) {
        // configured successfully for consumerID3
    }
    @Override
    public void onError(@NonNull List<D1Exception> exceptions) {
        for (D1Exception ex : exceptions) {
            // Handle errors
        }
    }
}, coreCfg3, cardCfg3);
```

{% endcode %}
{% endtab %}

{% tab title="Android Kotlin" %}
{% code lineNumbers="true" %}

```kotlin
// --- Placeholders you already have in your app / DI ---
val activity: Activity = myActivity /* your Activity */
val oemPayType: OEMPayType = OEMPayType.GOOGLE_PAY /* e.g., OEMPayType.GOOGLE_PAY or SAMSUNG_PAY */
val samsungServiceId: String = "serviceID" /* your Samsung Pay service ID or "" if not used */
val visaClientAppId: String = "clientAppID" /* your Visa client app ID or "" if not used */

// --- D1Task declarations ---
lateinit var d1Task1: D1Task // Uses ISSUER_ID_1 issuerToken with CONSUMER_ID_1
lateinit var d1Task2: D1Task // Uses ISSUER_ID_1 issuerToken with CONSUMER_ID_2
lateinit var d1Task3: D1Task // Uses ISSUER_ID_2 issuerToken with CONSUMER_ID_3

// --- Consumer IDs ---
val consumerID1 = "CONSUMER_ID_1"
val consumerID2 = "CONSUMER_ID_2"
val consumerID3 = "CONSUMER_ID_3"

// --- Build common per-task config params ---
val cardCfg1: D1Params = ConfigParams.buildConfigCard(activity, oemPayType, samsungServiceId, visaClientAppId)
val cardCfg2: D1Params = ConfigParams.buildConfigCard(activity, oemPayType, samsungServiceId, visaClientAppId)
val cardCfg3: D1Params = ConfigParams.buildConfigCard(activity, oemPayType, samsungServiceId, visaClientAppId)

fun makeConfigCallback(tag: String) = object : D1Task.ConfigCallback<Void?> {
    override fun onSuccess(data: Void?) {
        // configured successfully for $tag
    }
    override fun onError(exceptions: List<D1Exception>) {
        for (ex in exceptions) {
            // Handle errors as per "D1 SDK Integration – Error Management"
            // e.g., log/route by ex.code, ex.message
        }
    }
}

// --- Configure d1Task1 ---
val coreCfg1: D1Params = ConfigParams.buildConfigCore(consumerID1)
d1Task1.configure(
    makeConfigCallback("consumerID1"),
    coreCfg1,
    cardCfg1
)

// --- Configure d1Task2 ---
val coreCfg2: D1Params = ConfigParams.buildConfigCore(consumerID2)
d1Task2.configure(
    makeConfigCallback("consumerID2"),
    coreCfg2,
    cardCfg2
)

// --- Configure d1Task3 ---
val coreCfg3: D1Params = ConfigParams.buildConfigCore(consumerID3)
d1Task3.configure(
    makeConfigCallback("consumerID3"),
    coreCfg3,
    cardCfg3
)
```

{% endcode %}
{% endtab %}

{% tab title="iOS" %}
{% code overflow="wrap" lineNumbers="true" %}

```swift
var d1Task1: D1Task! // Uses ISSUER_ID_1 issuerToken with CONSUMER_ID_1
var d1Task2: D1Task! // Uses ISSUER_ID_1 issuerToken with CONSUMER_ID_2
var d1Task3: D1Task! // Uses ISSUER_ID_2 issuerToken with CONSUMER_ID_3

// Setup d1Task1
var comp = D1Task.Components()
comp.issuerID = "ISSUER_ID_1"
// set up other variables, e.g. URL
d1Task1 = comp.task()

// Setup d1Task2 (same issuerID as d1Task1)
comp = D1Task.Components()
comp.issuerID = "ISSUER_ID_1"
// set up other variables, e.g. URL
d1Task2 = comp.task()

// Set up d1Task3 (different issuerID)
comp = D1Task.Components()
comp.issuerID = "ISSUER_ID_2"
// set up other variables, e.g. URL
d1Task3 = comp.task()

// Initialize SDK for different D1Task instances and consumer IDs
let consumerID1 = "CONSUMER_ID_1"
let consumerID2 = "CONSUMER_ID_2"
let consumerID3 = "CONSUMER_ID_3"

// D1Task1 configure
let coreConfig1 = ConfigParams.coreConfig(consumerID: consumerID1)
let cardConfig1 = ConfigParams.cardConfig()
d1Task1.configure([coreConfig1, cardConfig1]) { errors in
    if let errors = errors {
        for error in errors {
            // Handle errors as per D1 SDK Integration – Error Management documentation
        }
    }
}

// D1Task2 configure
let coreConfig2 = ConfigParams.coreConfig(consumerID: consumerID2)
let cardConfig2 = ConfigParams.cardConfig()
d1Task2.configure([coreConfig2, cardConfig2]) { errors in
    if let errors = errors {
        for error in errors {
            // Handle errors as per D1 SDK Integration – Error Management documentation
        }
    }
}

// D1Task3 configure
let coreConfig3 = ConfigParams.coreConfig(consumerID: consumerID3)
let cardConfig3 = ConfigParams.cardConfig()
d1Task3.configure([coreConfig3, cardConfig3]) { errors in
    if let errors = errors {
        for error in errors {
            // Handle errors as per D1 SDK Integration – Error Management documentation
        }
    }
}
```

{% endcode %}
{% endtab %}
{% endtabs %}

#### Log in with multiple issuer access tokens

The `sub` claim of an issuer access token can contain multiple consumer IDs.

When present, separate the consumer IDs with spaces.

Example issuer access tokens:

{% code overflow="wrap" lineNumbers="true" %}

```java
{
  "jti": "M9JHKtLdfXu782EH3hMf_",
  "sub": "CONSUMER_ID_1 CONSUMER_ID_2",
  "iat": 1626836247,
  "exp": 1627441047,
  "scope": "digibank:mobilebanking digibank:ecommerce",
  "iss": "ISSUER_ID_1",
  "aud": "https://client-api.d1.thalescloud.io/oidc/ISSUER_ID_1"
}

{
  "jti": "M9JHKtLdfXu782EH3hMf_",
  "sub": "CONSUMER_ID_3",
  "iat": 1626836247,
  "exp": 1627441047,
  "scope": "digibank:mobilebanking digibank:ecommerce",
  "iss": "ISSUER_ID_2",
  "aud": "https://client-api.d1.thalescloud.io/oidc/ISSUER_ID_1"
}
```

{% endcode %}

The first issuer access token for `ISSUER_ID_1` includes `CONSUMER_ID_1` and `CONSUMER_ID_2`.

The second issuer access token for `ISSUER_ID_2` includes `CONSUMER_ID_3`.

You can call the login API from any previously created `D1Task` instance. After that, subsequent operations can continue without another login.

{% tabs %}
{% tab title="Android Java" %}
{% code lineNumbers="true" %}

```java
String cbp = d1Task1.getBindingHash(); // Must be called if client binding is enabled.

// TODO: replace with the issuer access token returned by your issuer backend. 
// The token must include cbp as a claim, if client binding is enabled.
byte[] issuerToken1 = new byte[0]; 
byte[] issuerToken2 = new byte[0]; 

// Build the list of tokens
List<byte[]> tokens = new ArrayList<>();
tokens.add(issuerToken1);
tokens.add(issuerToken2);

// Do a single login using d1Task1 and all issuer access tokens
d1Task1.login(tokens, new D1Task.Callback<Void>() {
    @Override
    public void onSuccess(Void ignored) {
        // Login successful — proceed with subsequent operations

        final String cardId1 = "CARD_ID_1";
        final String cardId2 = "CARD_ID_2";
        final String cardId3 = "CARD_ID_3";

        d1Task1.getCardMetadata(cardId1, new D1Task.Callback<CardMetadata>() {
            @Override
            public void onSuccess(CardMetadata data) {
                // Use metadata for task1
            }

            @Override
            public void onError(@NonNull D1Exception exception) {
                // Handle error for task1 metadata
            }
        });

        d1Task2.getCardMetadata(cardId2, new D1Task.Callback<CardMetadata>() {
            @Override
            public void onSuccess(CardMetadata data) {
                // Use metadata for task2
            }

            @Override
            public void onError(@NonNull D1Exception exception) {
                // Handle error for task2 metadata
            }
        });

        d1Task3.getCardMetadata(cardId3, new D1Task.Callback<CardMetadata>() {
            @Override
            public void onSuccess(CardMetadata data) {
                // Use metadata for task3
            }

            @Override
            public void onError(@NonNull D1Exception exception) {
                // Handle error for task3 metadata
            }
        });
    }

    @Override
    public void onError(@NonNull D1Exception exception) {
        // Handle login error
    }
});
```

{% endcode %}
{% endtab %}

{% tab title="Android Kotlin" %}
{% code lineNumbers="true" %}

```kotlin
val cbp = d1Task1.getBindingHash() // Must be called if client binding is enabled.

// TODO: replace with the issuer access token returned by your issuer backend. 
// The token must include cbp as a claim, if client binding is enabled.
val issuerToken1: ByteArray = byteArrayOf() 
val issuerToken2: ByteArray = byteArrayOf() 

// Build the list of tokens
val tokens = mutableListOf<ByteArray>()
tokens += issuerToken1
tokens += issuerToken2

// Single login using d1Task1 with all issuer access tokens
d1Task1.login(tokens, object : D1Task.Callback<Void?> {
    override fun onSuccess(data: Void?) {
        // Login successful — proceed with subsequent operations

        val cardId1 = "CARD_ID_1"
        val cardId2 = "CARD_ID_2"
        val cardId3 = "CARD_ID_3"

        d1Task1.getCardMetadata(cardId1, object : D1Task.Callback<CardMetadata> {
            override fun onSuccess(data: CardMetadata) {
                // Use metadata for task1
            }
            override fun onError(exception: D1Exception) {
                // Handle error for task1 metadata
            }
        })

        d1Task2.getCardMetadata(cardId2, object : D1Task.Callback<CardMetadata> {
            override fun onSuccess(data: CardMetadata) {
                // Use metadata for task2
            }
            override fun onError(exception: D1Exception) {
                // Handle error for task2 metadata
            }
        })

        d1Task3.getCardMetadata(cardId3, object : D1Task.Callback<CardMetadata> {
            override fun onSuccess(data: CardMetadata) {
                // Use metadata for task3
            }
            override fun onError(exception: D1Exception) {
                // Handle error for task3 metadata
            }
        })
    }

    override fun onError(exception: D1Exception) {
        // Handle login error
    }
})
```

{% endcode %}
{% endtab %}

{% tab title="iOS" %}
{% code overflow="wrap" lineNumbers="true" %}

```swift
do {
    let cbp = try await d1Task1.bindingHash() // Must be called if client binding is enabled.
    
    // TODO: replace with the issuer access token returned by your issuer backend.
    // The token must include cbp as a claim, if client binding is enabled.
    let issuerToken1 = Data() 
    let issuerToken2 = Data()
    var tokens = [issuerToken1, issuerToken2]

    // Use any configured D1Task instance for a single login call.
    try await d1Task1.login(&tokens)
    // Login successful
} catch {
    // Handle login error
}

d1Task1.cardMetadata(d1Task1.cardId) { metaData, error in
    if let error = error {
        // Handle error
    } else {
        // Use metadata
    }
}

d1Task2.cardMetadata(d1Task2.cardId) { metaData, error in
    if let error = error {
        // Handle error
    } else {
        // Use metadata
    }
}

d1Task3.cardMetadata(d1Task3.cardId) { metaData, error in
    if let error = error {
        // Handle error
    } else {
        // Use metadata
    }
}
```

{% endcode %}
{% endtab %}
{% endtabs %}

### Invalidate all issuer access tokens

To invalidate all tokens for all configured `D1Task` instances, use [SDK logout](broken://spaces/62lLFDcmLCeqqwmy4Fee/pages/UAcJzNrCmjg0IstElB9y).


---

# 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, and the optional `goal` query parameter:

```
GET https://docs.payments.thalescloud.io/click-to-pay/es/integrate-the-d1-sdk/getting-started/configuration/5.-authentication/sdk-login/iniciar-sesion-en-multiples-usuarios-finales-y-emisores.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

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.
