NAV Navbar
Javascript Java C#

TPP On-boarding

Getting Started in the Sandbox

The sandbox is a virtual testing environment that mimics production. Here you can play around with fake banks and money so you can be sure your code works before accessing real accounts.

1. Samples and SDK

See working implementations of a payment flow (PISP) or how a PFM can access information (AISP), with our samples

Download the SDK in your preferred language.

2. Setting up the Client

The SDK shows how to set up an Token client that saves your user’s private keys in a directory named keys. If your code runs somewhere with a safer storage space, you can write a crypto engine that stores keys elsewhere, using UnsecuredFileCryptoEngine as a guide.

The SDK shows how to set up an Token client that saves your user’s private keys in a directory named keys. If your code runs somewhere with a safer storage space, you can implement a IKeyStore that stores keys elsewhere, using UnsecuredFileSystemKeyStore as a guide.

Go here for information about Local Key Storage.

Creating the Client

Path keys = Files.createDirectories(Paths.get("./keys"));
TokenClient tokenClient = TokenClient.builder()
        .withKeyStore(new UnsecuredFileSystemKeyStore(keys.toFile()))
        .connectTo(SANDBOX)
        .build();
const Token = new TokenClient({
    env: 'sandbox',
    keyDir: './keys',
});
 Tokenio.Tpp.TokenClient tokenClient = Tokenio.Tpp.TokenClient.NewBuilder()
.ConnectTo(Tokenio.TokenCluster.SANDBOX)
.WithKeyStore(new UnsecuredFileSystemKeyStore(key.FullName))
.Build();

Relevant API:

3. Creating a Business Member

Before connecting to banks through TokenClient, you must first create a Token business member using the createMember method with the type DOMAIN.

NOTE: If you have already created a member, load your existing member. Otherwise, you will need to set up an alias along with your member.

Creating a Business Member

// the 2nd time it will fail because the name is taken.)
//
// In test environments, we can use this domain as an alias
// without verifying it; but in production, we can't.
const alias = {
    type: 'DOMAIN',
    value: `${Token.Util.generateNonce()}.com.noverify`,
};

// Create a member with keys stored in memory:
return await Token.createMember(
/**
 * Creates and returns a new token member.
 *
 * @return a new Member instance
 */
public static Member createMember() {
    // Create the client, which communicates with
    // the Token cloud.
{
    /// <summary>
    /// Creates and returns a new token member.
    /// </summary>
    /// <returns>a new Member instance</returns>
    public static TppMember CreateMember()

Relevant APIs:

4. Aliases and Verification

Members have human-readable and verifiable aliases. As a Token business member with the DOMAIN type, you must provide your business web domain as your alias.

An alias can only be claimed once. After that, it is no longer available to other members. An alias belongs to only one (1) member, and must be verified before it can be used.

Adding and Removing an Alias

Alias alias = Alias.newBuilder()
        .setType(DOMAIN)
        .setValue("verified-domain.com")
        .build();

// add the alias
member.addAliasBlocking(alias);

// remove the alias
member.removeAliasBlocking(alias);
const alias1 = (await member.aliases())[0]; // or member.firstAlias();
const alias2 = {
    type: 'EMAIL',
    value: 'alias2-' + Token.Util.generateNonce() + '+noverify@token.io',
};
await member.addAlias(alias2);

const alias3 = {
    type: 'EMAIL',
    value: 'alias3-' + Token.Util.generateNonce() + '+noverify@token.io',
};
const alias4 = {
    type: 'EMAIL',
    value: 'alias4-' + Token.Util.generateNonce() + '+noverify@token.io',
};
await member.addAliases([alias3, alias4]);

await member.removeAlias(alias1);
await member.removeAliases([alias2, alias3]);

Alias alias = new Alias
{
    Type = Alias.Types.Type.Domain,
    Value = "verified-domain.com"

};
// add the alias
member.AddAliasBlocking(alias);
// remove the alias
member.RemoveAliasBlocking(alias);

Verifying an Alias

DOMAIN type aliases need to be manually verified by Token. To register a domain alias:

  1. Add your domain name using the Member addAlias method.

  2. Send Token a message that includes your business member ID.

If you do not know your ID, you can retrieve it using the Member memberId method.

Relevant APIs:

Fetching an Alias

There are two ways to fetch aliases:

  1. Fetch a list of the member’s aliases by calling the Member aliases method.
  2. Fetch the first alias used by the member by calling the Member firstAlias convenience method.

Relevant APIs:

Resolving an Alias

To resolve a member’s identity, you can look up a member’s ID using their alias and/or profile.

If you want to find out if an alias already belongs to a member, call the resolveAlias method. This can be helpful in discovering if there is a typo.

Relevant APIs:

Resolving an Alias

const resolved = await Token.resolveAlias(alias4);
/* resolved alias has id and alias fields: */
{
"id": "m:4AaVmfKfY9DQ9tuqWJcEwq9VkXpo:5zKtXEAq",
"alias": {
  "type":"EMAIL",
  "value":"alias4-v6rpfo+noverify@token.io"}
  }
}
Alias alias = Alias.newBuilder()
        .setValue("user-email@example.com")
        .build();

// If this call fails then the alias does not correspond to an existing member.
TokenMember resolved = client.resolveAliasBlocking(alias);

// resolved member ID from alias
String memberId = resolved.getId();

// The resolved alias
// will have the correct type, e.g. EMAIL.
Alias resolvedAlias = resolved.getAlias();
{
    Alias alias = new Alias
    {
        Value = "user-email@example.com"

    };


    // If this call fails then the alias does not correspond to an existing member.
    TokenMember resolved = client.ResolveAliasBlocking(alias);

    // resolved member ID from alias
    string memberId = resolved.Id;

    // The resolved alias
    // will have the correct type, e.g. EMAIL.
    Alias resolvedAlias = resolved.Alias;

5. Load Existing Member

To obtain a Member object for an already-existing member, you must have a TokenClient, the member ID of an existing member, AND the member’s keys. Add the keys to your SDK’s keystore and then call TokenClient.getMember on the member ID.

This code uses the API:

Most of the newly created member data is stored in the Token cloud, such as public keys. Private keys remain in local storage.

Use already-stored private key

return tokenClient.getMemberBlocking(memberId);
member = Token.getMember(Token.UnsecuredFileCryptoEngine, mid);
return tokenClient.GetMember(memberId);

6. Profile

Each business member has a profile that allows users to find the member they are searching for without the alias or ID. This display name must be your business name. This identifies you in push notifications sent to your users’ apps, avoiding confusion and unintentional purchase cancellations. E.g. “Southside is requesting €10” as opposed to “Unknown merchant is requesting €10”.

Getting the Profile

To get member profile information, call Member getProfile. This gets a Profile data structure containing the member’s display name.

Relevant APIs:

Setting the Profile Picture

Call Member setProfile method to set your display name. This method takes a Profile data structure.

Relevant APIs:

Example for Setting the Profile

const name = {
    displayNameFirst: 'Tycho',
    displayNameLast: 'Nestoris',
};
await member.setProfile(name);
const jpeg = loadPicture('tycho.jpg'); // file contents as byte array
await member.setProfilePicture('image/jpeg', jpeg);

const profile = await member.getProfile(member.memberId());
/* Profile structure: */
{
 displayNameFirst: 'Tycho',
 displayNameLast: 'Nestoris',
 originalPictureId: 'b:2aT7GiHkqhDzpLw...rfBaag4jw:5zKtXEAq'
}
Profile name = Profile.newBuilder()
        .setDisplayNameFirst("Tycho")
        .setDisplayNameLast("Nestoris")
        .build();
member.setProfileBlocking(name);
member.setProfilePictureBlocking("image/jpeg", PICTURE);

Profile profile = member.getProfileBlocking(member.memberId());
Profile name = new Profile
{
    DisplayNameFirst = "Tycho",
    DisplayNameLast = "Nestoris"
};

member.SetProfileBlocking(name);
member.SetProfilePictureBlocking("image/jpeg", PICTURE);

Profile profile = member.GetProfileBlocking(member.MemberId());

7. Keys

Each member has cryptographic keys used to endorse or sign a token.

When you create a member with the createMember method, it automatically creates three (3) key pairs:

  1. a low-level pair
  2. a standard pair
  3. a privileged pair

Each pair has a private and a public key. The three public keys are uploaded to the Token cloud; the private keys are put into secure local storage.

The private keys will be used to sign all requests made through the Member object, such as initiating requests for account access or payments, or changing the Member’s profile. Token will verify each request using the public keys. Requests made directly from the TokenClient, such as resolving an alias or retrieving a list of connected banks, are not signed and are therefore accessible by anyone.

The following methods control keys in the Token Cloud ONLY.

To add more keys: call the Member approveKey or Member approveKeys method.

To remove previously-uploaded keys, call Member removeKey or Member removeKeys.

IMPORTANT: Removed keys are no longer valid and cannot be used to sign requests.

Relevant APIs:

Generating, Approving, and Removing Keys

Key lowKey = crypto.generateKey(LOW);
member.approveKeyBlocking(lowKey);

Key standardKey = crypto.generateKey(STANDARD);
Key privilegedKey = crypto.generateKey(PRIVILEGED);
member.approveKeysBlocking(Arrays.asList(standardKey, privilegedKey));

member.removeKeyBlocking(lowKey.getId());
const keypair4 = await Token.Crypto.generateKeys('LOW');
keypair4.publicKey = Util.strKey(keypair4.publicKey);
await member.approveKey(keypair4);
const keypair5 = await Token.Crypto.generateKeys('STANDARD');
const keypair6 = await Token.Crypto.generateKeys('PRIVILEGED');
keypair5.publicKey = Util.strKey(keypair5.publicKey);
keypair6.publicKey = Util.strKey(keypair6.publicKey);
await member.approveKeys([keypair5, keypair6]);

await member.removeKey(keypair4.id);
await member.removeKeys([keypair5.id, keypair6.id]);
Key lowKey = crypto.GenerateKey(Key.Types.Level.Low);
member.ApproveKeyBlocking(lowKey);

Key standardKey = crypto.GenerateKey(Key.Types.Level.Standard);
Key privilegedKey = crypto.GenerateKey(Key.Types.Level.Privileged);

Local Key Storage

To configure where the client stores member’s private keys, choose a CryptoEngine type and pass it as a parameter to Token.createMember, Token.provisionDevice, and Token.provisionDeviceLow.

The Token SDK client class provides some built-in key storage CryptoEngine types:

  • Token.MemoryCryptoEngine keeps keys in memory and forgets them on restart, which is useful for unit tests, but not for persistent members.
  • Token.UnsecuredFileCryptoEngine keeps keys in files in a directory. You must specify which directory as a parameter when creating the Token SDK client.
  • Token.BrowserCryptoEngine keeps keys in browser’s localStorage, which is useful for web clients.

You can define another CryptoEngine key storage type if you don’t want to use the one above. One option for implementation is the BrowserCryptoEngine implementation - a thin wrapper around BrowserKeyStore and stores keys. Use the KeyStoreCryptoEngine helper class to ease defining a similar, thin, wrapper.

For more information about implementing a custom CryptoEngine, see the SDK’s README.

Relevant APIs:

To configure where the client stores member’s private keys, choose the KeyStore implementation and pass it as a parameter to TokenClient.builder().withKeyStore().

The Token SDK client class provides basic built-in KeyStore classes:

  • InMemoryKeyStore keeps keys in memory, but forgets on restart. This is useful for unit tests, but not for persistent members.
  • UnsecuredFileSystemKeyStore keeps keys in files in a directory. You must specify which directory as a constructor parameter.

You can define another KeyStore class if you don’t want to use the one above.

Relevant APIs:

To configure where the client stores member’s private keys, choose the IKeyStore implementation and pass it as a parameter to TokenClient.Builder.WithKeyStore().

The Token client class provides basic built-in IKeyStore classes:

  • InMemoryKeyStore keeps keys in memory, and forgets on restart. This is useful for unit tests, but not for persistent members.
  • UnsecuredFileSystemKeyStore keeps keys in files in a directory. You must specify which directory as a constructor parameter.

You can define another IKeyStore class if you don’t want to use the one above.

Going into Production

When your code is ready for production, you have two options:

If you are using your own eIDAS certificate, follow the eIDAS verification instructions below.

Otherwise refer to the manual registration instructions.

eIDAS Verification

Third Party Providers (TPPs) are required to identify themselves to banks using their QSEAL (Qualified Certificate for Electronic Seals) eIDAS (electronic IDentification Authentication Services ) to receive access to their bank’s sandbox and APIs.

This flow is designed to allow TPPs to gain access to one particular bank without manual verification. In order to be verified, you must do the following:

  1. Set up the Client.

  2. Call createMember under the realm of the bank you wish to gain access to, specifying the memberId of the bank (i.e the realmId should be equal to the bank’s memberId).

  3. Call the addAlias method with the type eIDAS under the same realm. Set the value equal to your TPP authNumber which can be found in the certificate.

  4. Verify your eIDAS certificate by calling verifyEidas. The payload should be signed with the private key that corresponds to the public key in the certificate.

    The input takes the following two parameters:

    payload includes memberId, eIDAS alias, base64 encoded eIDAS certificate, and a signing algorithm used to sign the certificate.
    signature the above payload signed with the private key corresponding to the given certificate

    The method returns VerifyEidasResponse which contains verification status with possible values:

    SUCESS Your request was successful.
    FAILURE_EIDAS_INVALID Your certificate is invalid.
    FAILURE_ERROR_RESPONSE The verification service returned an error response.

It also returns string with the status details about an error that occurred or the validity of the certificate.

If the request is successful and the provided certificate is valid, the TPP member and their eIDAS alias become verified and get the permissions listed in the certificate.

NOTE: If you want to update your certificate validation, you need to reverify your alias with your new certificate.

NOTE: The certificate is revalidated periodically. If it becomes invalid (e.g. expired) the TPP member becomes unverified and loses all the permissions that had been previously granted.

Create Member and verify eIDAS Sample (Currently available only in Java)

public static Member verifyEidas(
        TokenClient client,
        String tppAuthNumber,
        String certificate,
        String bankId,
        PrivateKey privateKey) {
    Algorithm signingAlgorithm = Algorithm.RS256;
    Crypto crypto = CryptoRegistry.getInstance().cryptoFor(signingAlgorithm);
    Signer signer = crypto.signer("eidas", privateKey);

    // resolve memberId of the bank TPP is trying to get access to
    String bankMemberId = client
            .resolveAliasBlocking(Alias.newBuilder().setValue(bankId).setType(BANK).build())
            .getId();
    // create an eIDAS alias under realm of the target bank
    Alias eidasAlias = normalize(Alias.newBuilder()
            .setValue(tppAuthNumber)
            .setRealmId(bankMemberId)
            .setType(EIDAS)
            .build());
    // create a member under realm of the bank with eIDAS alias
    Member tpp = client.createMember(eidasAlias, null, bankMemberId).blockingSingle();
    // construct a payload with all the required data
    VerifyEidasPayload payload = VerifyEidasPayload
            .newBuilder()
            .setAlgorithm(signingAlgorithm)
            .setAlias(eidasAlias)
            .setCertificate(certificate)
            .setMemberId(tpp.memberId())
            .build();
    // verify eIDAS
    VerifyEidasResponse response = tpp
            .verifyEidas(payload, signer.sign(payload))
            .blockingSingle();
    return tpp;
}

Manual Registration

  1. When you are ready for production, connect to the production environment by updating connectTo(SANDBOX) to connectTo(PRODUCTION) or prd if you are using JavaScript.

  2. For verification, Token will need your Alias value and type, and your memberId.

  3. Contact Token Support using the TPP On-boarding category. A support ticket will be generated for you.

  4. Token will perform KYC (Know Your Customer) compliance checks, including checking your eIDAS credentials. Token will also verify your domain alias at this time.

  5. When this process is complete, you will be informed through your support ticket.

What’s Next?

PIS

Go HERE for PIS related functionality such as initiating a payment.

AIS

Go HERE for AIS related functionality such as accessing customer account information.

CBPII

Go HERE for CBPII related functionality.

Copyright © 2019 Token, Inc. All Rights Reserved