NAV Navbar
Javascript Java C#

Access Banks

This page is for developers building applications that need to initiate payments and access account information from Token-connected banks. The page is organized in sections of customer experience, integration steps, sample code and access to the SDKs. And don’t forget to review the Security Considerations section!

A key concept of TokenOS is the “Smart Token”, which is a digital authorizations to access an underlying asset (e.g. bank accounts) to initiate a payment or access information.

Smart Tokens are REQUESTED, CREATED and finally REDEEMED (or cancelled). You’ll find more details about Smart Tokens in the section Flow Overview.

If you have questions or feedback about these docs, please contact us https://token.io/contact.

About TokenOS

TokenOS is the operating system for open banking that allows banks, merchants, enterprises and individuals to interact in a global marketplace of financial services.

Token Ecosystem

TokenOS provides third parties with lower cost payments, new payment propositions, richer customer spend data and a better user experience for their customers. TokenOS easily integrates with a third party’s existing infrastructure using SDKs provided in common languages.

Key benefits include:

Third parties connect to banks through an open and secure API. TokenOS connects to banks through various methods, but provides a single, unified interface for developers. Contact us for a list of banks that TokenOS currently connect to.

Customer Experience

Depending on the underlying bank and its authentication and authorization method, the user experience may vary. The following screens are representative of most cases.

Example UX of a merchant requesting a bank direct payment using Token; the user is visiting the merchant website on a mobile device.

Screen 0 Screen 1 Screen 2 Screen 3 Screen 4 Screen 5 Screen 7 Screen 8

Integration Steps

Getting Started

To start making Token API calls, first setup your back-end service. Download the latest Token SDK and set up a client. To start accepting payments or accessing information using TokenOS, you must first create a Token Business Member account. Your back-end service will use this member’s credentials to initiate API calls and request Smart Tokens for payments and information access.

To create a Token Business Member, you’ll need to specify a domain to use as your member’s alias (in the example below, a randomly generated domain is provided). It’s also recommended to specify a display name, which will be shown to the end-user when requesting authorization to initiate a payment or access account information.

domain Domain of your organization. This will need to be verified so that the user knows who he is approving access to.
member Token member. Used to make authenticated API calls to TokenOS.

Example call to create a business-type member.

const domain = Math.random().toString(36).substring(2, 10) + ".com"
const alias = {
    type: DOMAIN,
    value: domain
};
Token.createBusinessMember(alias, Token.UnsecuredFileCryptoEngine).then(function(m) {
    member = m;
    member.setProfile({
        displayNameFirst: 'Merchant 123'
    });
});
String domain = generateNonce() + ".com";
Alias alias = Alias.newBuilder()
        .setType(DOMAIN)
        .setValue(domain)
        .build();
Member member = tokenClient.createMemberBlocking(alias);
member.setProfileBlocking(Profile.newBuilder()
        .setDisplayNameFirst("Merchant 123")
        .build());
string domain = Util.Nonce() + ".com";
Alias alias = new Alias
{
    Type = Domain,
    Value = domain
};
Member member = tokenClient.CreateBusinessMember(alias).Result;
var profile = new Profile
{
    DisplayNameFirst = "Merchant 123"
};
member.SetProfile(profile).Result;

If you already have a member created, you should load your existing member.

Flow Overview

At the core of TokenOS is the Smart Token. Smart Tokens are digital authorizations to access an underlying asset (e.g. bank accounts). There are two common use cases:

  1. Smart Tokens to access end-user bank account information (access tokens)
  2. Smart Tokens to initiate payments from end-user bank accounts (transfer tokens)

To obtain a Smart Token, you must request it from the user via the Smart Token Request Flow, an OAuth-like flow that can be easily embedded in any third party website or mobile application.

Token Request Flow Sequence Diagram

At a high level, the Smart Token Request Flow consists of three steps. In the remainder of this document, the word token is used interchangeably with Smart Token for brevity.

1. Create a token request.
POST /token-request
- Front-end sends a request for access or payment to the back-end.
- Back-end service creates a tokenRequest and constructs tokenRequestUrl.
- Back-end service responds with HTTP 303 requesting redirect to tokenRequestUrl.
2. Redirect to TokenOS to obtain authorization. - Front-end visits tokenRequestUrl.
- User proceeds through TokenOS steps.
- TokenOS redirects to callback URL hosted by TPP back-end service (specified in the tokenRequest from Step 1).
3. Redeem the token.
GET /accounts/{accountId}/balance
GET /accounts/{accountId}/transactions
PUT /accounts/{accountId}/funds-confirmation
PUT /tokens/{tokenId}/redeem
- Back-end service parses callback URL and obtains tokenId.
- Back-end service uses tokenId for payment initiation or access to account information.

1. Create a Token Request

TokenOS handles the creation of the token. It manages user authentication and consent, and is designed to abstract away the complexity of the underlying bank connections. In order to request a token, first create a TokenRequest, which contains all the information that will be in the final token (payment amount, account information permissions, etc.).

The contents of the TokenRequest will differ depending on the type of token being requested. Since the member creating the TokenRequest must match the member that redeems the token later in the flow, you should perform TokenRequest creation server-side.

A TokenRequest expires in a short period of time, so you should use it immediately. A TokenRequest consists of the following fields:

to Recipient of the token, specifiable by member ID or alias.
description Description of the payment or access.
redirectUrl Defines the callback URL where your server will initiate redemption of the token.
refId Reference ID for the token.
callbackState Developer-specified string that allows state to be persisted between the the request and callback phases of the flow.
AccessBody or TransferBody Information specific to an access token or transfer token; see below.
actingAs Optional. Entity that the to member is acting as a proxy for.
destinationCountry Optional. Used to narrow down the country selection in the web-app UI.
userRefId Optional. Used to track a member claimed by a TPP.
customizationId Optional. Used for customizing the UI of the web-app.
bankId Optional. Specify if you would like to bypass the Token bank selection UI. See below for more details.
from Optional. Specify if you would like to bypass the Token email input UI. See below for more details.
sourceAccountId Optional. The account ID of the source bank account.
receiptRequested Optional. True if a receipt should be sent to the from member’s default receipt email (or phone, etc.)

A RequestId will be returned on submission of the TokenRequest, which must be included in the URL when redirecting the user to Token to obtain the authorization. This ID references the stored TokenRequest and is used to verify that the conditions of the request are unchanged.


Transfer Tokens

To make a request for a transfer token, use TokenRequest.transferTokenRequestBuilder(amount, currency), where amount is the total lifetime amount of the token, and currency is the 3 letter (ISO4217) currency code (e.g. “EUR”). In addition to the above, the following two fields will be available on the transfer token request builder.

chargeAmount Single token charge request acceptable range.
destinations Destination account(s) for the payment. This will typically contain an IBAN for SEPA transfer, or Sort Code and Account Number for Faster Payments. Details about the TransferEndpoint object can be found here.

See our SDK Documentation for more information.

See our SDK Documentation for more information.

See our SDK Documentation for more information.

Though optional, we recommend setting a Reference ID in the tokenBuilder, which will be included in the request to transfer the funds. This allows merchants the ability to easily reconcile transactions against payments received to their account(s). Due to restrictions of particular payment rails, this value cannot exceed 18 characters in length.

An example of creating a TokenRequest for a transfer token

const payload = {
    to: {
        id: payee.memberId(),
    },
    transferBody: {
        lifetimeAmount: '10.00',
        currency: 'EUR',
    },
    description: 'Book Purchase',
    redirectUrl: 'https://tpp-website.com/callback',
};
const tokenRequest = Token.TokenRequest.create(payload)
    .setFromEmail('payerEmail@gmail.com')
    .setBankId('iron');

redeemer.storeTokenRequest(tokenRequest).then(function(res) {
        const requestId = res.id;
});
// Create token request to be stored
TokenRequest request = TokenRequest.transferTokenRequestBuilder(100.00, "EUR")
        .setTo(TokenMember.newBuilder()
                        .setId(payee.memberId())
                        .build())
        .setDescription("Book purchase") // optional description
        .setRedirectUrl("https://tpp-website.com/callback") // callback URL
        .setFrom(TokenMember.newBuilder()
                .setAlias(Alias.newBuilder()
                        .setValue("payer-email@example.com") // user alias
                        .setType(Alias.Type.EMAIL)
                        .build())
                .build())
        .setBankId("iron") // bank ID
        .build();

// Store the token request; obtain requestId
String requestId = payee.storeTokenRequest(request);
var storedPayload = new TokenRequestPayload
{
    UserRefId = tppRefId,
    RedirectUrl = tokenUrl,
    To = new TokenMember
    {
        Id = member.MemberId()
    },
    Description = "Book purchase",
    CallbackState = tppState,
    TransferBody = new TokenRequestPayload.Types.TransferBody
    {
        Amount = "10.0",
        Currency = "EUR"
    }
};

var storedOptions = new Tokenio.Proto.Common.TokenProtos.TokenRequestOptions
{
    BankId = "iron",
    ReceiptRequested = false,
    From = new TokenMember
    {
        Alias = new Alias
        {
            Type = Alias.Types.Type.Email,
            Value = "user@example.com"
        }
    }
};

var requestId = member.StoreTokenRequest(storedPayload, storedOptions).Result;


Access Tokens

To make a request for an access token, use TokenRequest.accessTokenRequestBuilder(resources), where resources is a list of the following ResourceTypes:

An example of creating a TokenRequest for an access token

// Construct payload
const payload = {
    to: {
        id: grantee.memberId(),
    },
    accessBody: {
        type: ['ACCOUNTS', 'BALANCES'],
    },
    redirectUrl: 'https://tpp-website.com/callback',
};

// Create token request to be stored
const tokenRequest = Token.TokenRequest.create(payload)
    .setFromEmail('grantorEmail@gmail.com')
    .setBankId('iron');

grantee.storeTokenRequest(tokenRequest).then(function(res) {
        const requestId = res.id;
});
// Create token request to be stored
TokenRequest request = TokenRequest.accessTokenRequestBuilder(ACCOUNTS, BALANCES)
        .setTo(TokenMember.newBuilder()
                .setId(grantee.memberId())
                .build())
        .setRedirectUrl("https://tpp-website.com/callback") // callback URL
        .setFrom(TokenMember.newBuilder()
                .setAlias(Alias.newBuilder()
                        .setValue("grantor-email@example.com") // user alias
                        .setType(Alias.Type.EMAIL)
                        .build())
                .build())
        .setBankId("iron") // bank ID
        .build();

// Store the token request; obtain requestId
String requestId = grantee.storeTokenRequest(request);
IList<ResourceType> types = new List<ResourceType>();
types.Add(ResourceType.Accounts);
var storedPayload = new TokenRequestPayload
{
    UserRefId = tppRefId,
    RedirectUrl = "https://tpp-website.com/callback",
    To = new TokenMember
    {
        Id = member.MemberId()
    },
    CallbackState = tppState,
    AccessBody = new TokenRequestPayload.Types.AccessBody
    {
        Type = {types}
    }
};

var storedOptions = new Tokenio.Proto.Common.TokenProtos.TokenRequestOptions
{
    BankId = "iron",
    ReceiptRequested = false,
    From = new TokenMember
    {
        Alias = new Alias
        {
            Type = Alias.Types.Type.Email,
            Value = "user@example.com"
        }
    }
};

var requestId = member.StoreTokenRequest(storedPayload, storedOptions).Result;

2. Redirect to TokenOS to obtain authorization

After creating a TokenRequest, construct a URL to direct your user to the Token web app. The Token SDK provides an easy way to do this.

tokenRequestUrl URL to TokenOS that guides your user through the necessary steps to create a token.
requestId ID that references a previously created TokenRequest stored in TokenOS.

An example of constructing a Token Request URL

const tokenRequestUrl = Token.generateTokenRequestUrl(requestId);
String tokenRequestUrl = tokenClient.generateTokenRequestUrlBlocking(requestId);
string tokenRequestUrl = tokenClient.GenerateTokenRequestUrl(requestId).Result;

After constructing your Token Request URL, direct your front-end to visit that URL. There are two different ways you can do this:

Server-side Redirect

Send an HTTP POST to your back-end to initiate the Token Request creation in Step 1 and redirect using an HTTP 302.

Binding the Token Button

You may also create a Token Button that either redirects to, or creates a popup of the Token web app in the user’s browser.

Create Redirect Button

function createRedirectButton() {
    var Token = new window.Token({
        env: 'sandbox',
    });

    // create TokenPopupController to handle Popup messages
    tokenController = Token.createRedirectController();

    // get button placeholder element
    var element = document.getElementById(elementId);

    // create the button
    button = window.Token.createTokenButton(element, {
        label: "Redirect Token Quick Checkout",
    });

    // bind the Token Button to the Redirect Controller when ready
    tokenController.bindButtonClick(button, function(action) {
        // Each time the button is clicked, a new tokenRequestUrl is created
        getTokenRequestUrl(function(tokenRequestUrl) {
            // Redirect to the Token web app with the generated tokenRequestUrl
            action(tokenRequestUrl);
        });
    });
    // enable button after binding
    button.enable();
}

Create Popup Button

function createPopupButton() {

    var Token = new window.Token({
        env: 'sandbox',
    });
    // create TokenPopupController to handle Popup messages
    tokenController = Token.createPopupController();

    // get button placeholder element
    var element = document.getElementById(elementId);

    // create the button
    button = Token.createTokenButton(element, {
        label: "Popup Token Quick Checkout",
    });

    // setup onLoad callback
    tokenController.onLoad(function(controller) {
        // bind the Token Button to the Popup Controller when ready
        tokenController.bindButtonClick(button, function(action) {
            // Each time the button is clicked, a new tokenRequestUrl is created
            getTokenRequestUrl(function(tokenRequestUrl) {
                // Initialize popup using the tokenRequestUrl
                action(tokenRequestUrl);
            });
        });
        // enable button after binding
        button.enable();
    });

    // setup onSuccess callback
    tokenController.onSuccess(function(data) { // Success Callback
        // build success URL
        var successURL = "/redeem"
            + "?tokenId=" + window.encodeURIComponent(data.tokenId);
        // navigate to success URL
        window.location.assign(successURL);
    });

    // setup onError callback
    tokenController.onError(function(error) { // Failure Callback
        throw error;
    });
}

For more information on these codes samples, please see the sample code below.

Example Token Request URL

https://web-app.token.io/request-token/rq:42w7yzgwJtN9fQVx78McJzEKiyU9:5zKtXEAq?lang=en

After the user is redirected to the request URL, they will be prompted to agree to the Token terms and conditions. After accepting, they will be taken to their bank where they will authenticate themselves and authorize the payment or data access transaction. Once the token has been created, it will redirect to the callback URL you specified in the TokenRequest with an HTTP 302.

Example TokenRequest Callback URL

https://merchant-site.com/callback?tokenId=tt:3PFXqSnRX7LCXo7MenmW26VVgMnHi44Br4WCM5MgEq4f:5zKxyCKM

TokenOS will include the necessary parameters for your server-side code to redeem the token in the callback URL.

Note: If you are integrating with a mobile app, you can initiate the Token Request creation in a WebView in Step 1 so the redirect is also in the form of an HTTP 302.

3. Redeem the Token

After obtaining user authorization, TokenOS will redirect to the callback URL specified in the TokenRequest with an HTTP 302. When your server-side code receives an HTTP GET request at the callback URL, it should use the Token SDK parseTokenRequestCallbackUrl method to extract the tokenId.

callbackUrl URL of HTTP request sent to the server callback endpoint.
tokenId ID that refers to a Token stored in TokenOS.

Example of parsing callback url

Token.parseTokenRequestCallbackUrl(callbackUrl).then(function(res) {
        const tokenId = res.tokenId;
})
String tokenId = tokenIO.parseTokenRequestCallbackUrl(callbackUrl).getTokenId();
string tokenId = tokenClient.ParseTokenRequestCallbackUrl(callbackUrl).Result.TokenId;

The Smart Token is an authorization. It must be redeemed to create a payment or access account information. If your token is a transfer token for a single payment, it only lasts a short period of time and should be redeemed immediately.


Redeem Transfer Tokens for Payment

Using the server-side Token member, call the redeemToken method to create a Transfer. This initiates a payment (via one of Token’s supported rails: e.g. SEPA) from the user’s bank.

tokenId ID that refers to a Token stored in TokenOS.
refID Optional. Client-supplied reference ID used for deduplicating requests.
transferToken A Token retrieved from TokenOS using a tokenId.
transfer Represents a payment. The status of the transaction can be retrieved using this object.

Example of transfer token redemption

//retrieve the token
payee.getToken(tokenId).then(function (transferToken){
        // Payee redeems a transfer token.
        // Money is transferred to a payee bank account.
        payee.redeemToken(transferToken, amount, currency, description, [], refId).then(function(transfer) {
                // Do something with transfer
        })
});
Token transferToken = payee.getTokenBlocking(tokenId); // retrieve the token

// Payee redeems a transfer token.
// Money is transferred to a payee bank account.
Transfer transfer = payee.redeemTokenBlocking(transferToken, refId);
Token transferToken = payee.GetToken(tokenId).Result; // retrieve the token

// Payee redeems a transfer token.
// Money is transferred to a payee bank account.
Transfer transfer = payee.RedeemToken(transferToken, refId).Result;

The transfer object (or its ID) returned can be used to retrieve the status of the transaction.

transferId ID that refers to a Transfer stored in TokenOS.
transfer A Transfer retrieved from TokenOS using a transferId or created with redeemToken.
status Represents a transaction status (processing, success, or failed).

Example of retrieving status of transfer

payee.getTransfer(transferId).then(function(transfer) {
        const status = transfer.status;
});
Transfer transfer = payee.getTransferBlocking(transferId);
TransactionStatus status = transfer.getStatus()
Transfer transfer = payee.GetTransfer(transferId).Result;
TransactionStatus status = transfer.Status;


Redeem Access Token for Account Information

Using your server member, call forAccessToken to get a Representable object that represents the user. You can then call getBalance, getTransactions, on the Representable object to retrieve account information. The methods will only succeed if the specified access token has sufficient permissions.

Due to certain bank connection limitations, TokenOS will sometimes cache data on schedule and return cached information unless otherwise specified.

grantee Member to whom the access token was granted.
tokenId ID that refers to an access token stored in TokenOS.
customerInitiated Optional. Flag to set if access is customer-initiated. This bypasses the TokenOS cache.
balance Balance of the account.

Example of access token redemption

const grantor = grantee.forAccessToken(tokenId);
const accounts = await grantor.getAccounts();
Representable grantor = grantee.forAccessToken(tokenId, false);
List<Account> grantorAccounts = grantor.getAccountsBlocking();

// Get the data we want
Money balance = grantorAccounts.get(0).getCurrentBalanceBlocking(STANDARD);
IRepresentable grantor = grantee.ForAccessToken(tokenId, false);
IList<Account> grantorAccounts = grantor.GetAccounts().Result;

// Get the data we want
Money balance = grantorAccounts[0].GetCurrentBalance(Standard).Result;

The forAccessToken method allows you to specify which access token to use to access information. You should keep track of the association between your access tokens and your users.

Download Sample Code

If you’d like to see a working implementation of the Smart Token Request Flow, check out our samples below:

Clone or download the appropriate sample. The README.md tells how to build and run the sample. Each sample contains a reference back-end service implementation as well as a reference front-end website.

Extensions

Optional: Display Your Own Bank Selection UI

The first screen your user will see when he is redirected to TokenOS is a bank selection screen, prompting him to choose the bank that he would like to use.

Banks Selection Screen

If you would like to filter the banks that are available to the user or control this bank selection UI in your own application, you can do so by specifying the bankId of the user-selected bank when creating the Token Request.

To retrieve the list of banks to display, use the getBanks method in the Token SDK.

Example of using getBanks

Token.getBanks().then(function(banks) {
        String bankId = banks[0].id;
})
List<Bank> banks = tokenClient.getBanksBlocking();
String bankId = banks.get(0).getId(); // take the first bank id
PagedBanks banks = tokenClient.GetBanks().Result;
string bankId = banks.Banks[0].Id;

Each bank also specifies additional properties described below. These properties can be used to filter the banks list displayed to the user.

supports_information Allows for retrieval of account information
supports_send_payment Allows for payment initiation
supports_receive_payment Allows for receiving payments
provider Underlying connectivity type; e.g. Yodlee FinAPI Token (direct integration)
country ISO 3166-1 alpha-2 two letter country code in uppercase.

After obtaining the user-selected bankId, provide it in the TokenRequest

Example of specifying bankId in tokenRequest creation

const tokenRequest = Token.TokenRequest.create(payload)
    .setBankId(bankId);
tokenRequest.setBankId(bankId);
var options = new TokenRequestOptions
{
    BankId = "iron"
};

When TokenOS displays this TokenRequest, it will see that a bankId has been specified and default to that bank instead of displaying the bank selection screen.

Optional: Provide User Email Address For Better UX

In the case of a Token Integrated bank , your user may be prompted to type in his email address in order to enable a customer experience that does not involve entering bank credentials.

Email Input Screen App Approval Screen

To provide an even more seamless experience, you have the option of specifying the user’s email address when creating the Token Request.

Example of specifying the user email address in tokenRequest creation

const tokenRequest = Token.TokenRequest.create(builder.build())
        .setRedirectUrl(redirectUrl)
        .setEmail(email)
// Create a TokenRequest to be stored
tokenRequest.setOption(REDIRECT_URL, redirectUrl)
      .setOption(ALIAS, emailAddress)
TokenRequest request = new TokenRequest
{
    Payload = tokenBuilder.BuildPayload(),
    // Configure options for the TokenRequest
    Options =
    {
        {TokenRequestOptions.redirectUrl.ToString(), redirectUrl},
        {TokenRequestOptions.alias.ToString(), emailAddress}
    }
};

By providing the email, TokenOS will skip the email input screen and ask the user to approve on his app directly, further reducing friction in the UX.

Optional: View Token Terms

Upon receiving a token, if you would like to check the terms of the token you can retrieve it with the getToken method and inspect the Token object returned.

Example of retrieving the token

payee.getToken(tokenId).then(function (token) {
        // Verify terms of the token
});
Token transferToken = payee.getTokenBlocking(tokenId);
Token transferToken = payee.GetToken(tokenId).Result;

Optional: Create a token on behalf of another party

If you are a business member and have been verified by Token to do so, you can create a token on behalf of another party. To do that you need to set the ActingAs field on the token payload with the following properties describing the intended recipient.

display_name Name of recipient, to be shown to user.
ref_id Optional. Your reference ID of the recipient. Opaque to Token.
logo_url URL pointing to recipient’s logo.
secondary_name Optional. Domain or email of the recipient, to be shown to user along with display_name.

Example of setting acting_as

// Transfer Token Request
const payload = {
    to: {
        id: payee.memberId(),
    },
    actingAs: {
        displayName: displayName,
        refId: refId,
        logoUrl: logoUrl,
        secondaryName: secondaryName,
    },
    transferBody: {
        lifetimeAmount: '100.00',
        currency: 'EUR',
    },
    description: 'Book purchase',
    redirectUrl: 'https://tpp-website.com/callback',
};

// Access Token Builder
const payload = {
    to: {
        id: grantee.memberId(),
    },
    actingAs: {
        displayName: displayName,
        refId: refId,
        logoUrl: logoUrl,
        secondaryName: secondaryName,
    },
    accessBody: {
        type: ['ACCOUNTS', 'BALANCES'],
    },
    redirectUrl: 'https://tpp-website.com/callback',
};

tokenRequest.setActingAs(ActingAs.newBuilder()
    .setDisplayName(displayName)
    .setRefId(refId)
    .setLogoUrl(logoUrl)
    .setSecondaryName(secondaryName));
// Transfer Token Builder
var payload = new TokenRequestPayload
{
    UserRefId = tppRefId,
    RedirectUrl = tokenUrl,
    To = new TokenMember
    {
        Id = member.MemberId()
    },
    ActingAs = new ActingAs
    {
        DisplayName = displayName,
        LogoUrl = logoUrl,
        RefId = refId,
        SecondaryName = secondaryName
    },
    Description = "Book purchase",
    CallbackState = tppState,
    TransferBody = new TokenRequestPayload.Types.TransferBody
    {
        Amount = "10.0",
        Currency = "EUR"
    }
};

// Access Token Builder
var payload = new TokenRequestPayload
{
    UserRefId = tppRefId,
    RedirectUrl = "https://tpp-website.com/callback",
    To = new TokenMember
    {
        Id = member.MemberId()
    },
    ActingAs = new ActingAs
    {
        DisplayName = displayName,
        LogoUrl = logoUrl,
        RefId = refId,
        SecondaryName = secondaryName
    },
    CallbackState = tppState,
    AccessBody = new TokenRequestPayload.Types.AccessBody
    {
        Type = {types}
    }
};

Security Considerations

Flow Overview

Since the Smart Token Request Flow is based on OAuth 2.0, we strongly recommended that you implement protection against CSRF and “OAuth Cut and Paste” (slides). TokenOS helps you mitigate both threats by providing a way to cryptographically bind CSRF tokens to the token ID.

This modifies the above outlined flow by introducing a step before the beginning of the process.

Token Request Flow Secure Sequence Diagram

0. Authenticate the Browser - Front-end authenticates with back-end service and creates a session.
1. Create a Token Request - Back-end service generates csrfToken as hash of session cookie, creates a tokenRequest, and constructs tokenRequestUrl
- Back-end service responds with HTTP 303 requesting redirect to tokenRequestUrl.
2. Redirect to TokenOS to obtain authorization - Front-end visits tokenRequestUrl.
- User proceeds through TokenOS steps.
- TokenOS redirects to callback URL hosted by your back-end service
3. Redeem the Token - Back-end service parses callback URL, validates csrfToken, and obtains tokenId and optional state.
- Back-end service uses tokenId to redeem to access account information or create a payment.

The Smart Token Request Flow is a web-based flow. In order to mitigate the above attacks, the first step is to authenticate your user in a web-based environment. In a typical application, the user is already logged in, so this may mean something different depending on if you are working with a website or a mobile application.

A web application does not need to implement anything additional if the user is already authenticated.

A mobile application will need to authenticate the user in the WebView. In order to avoid authenticating user on a separate web page you may want to share sessions between the mobile application and the WebView or use the existing mobile app session to create a new session in the WebView.

SDK Methods

There are two methods in the Token SDK to help with improving your application security.

String TokenIO.generateTokenRequestUrl(requestId, state, csrfToken)
Generates a Token Request URL that can be used to initiate the token request process. The state and csrfToken will be encoded in the URL.

TokenRequestCallback TokenIO.parseTokenRequestCallbackUrl(callbackUrl, csrfToken)
Parses a Token Request callback URL, validates the cryptographic signature binding the csrfToken, state, and tokenId, and returns the state.

csrfToken Unique string bound to the session of the user (e.g. the hash of a session cookie or associated with server-side user session). The csrfToken should be passed into both generateTokenRequestUrl and parseTokenRequestCallbackUrl to validate that the same user session initiated and completed the request.

TokenOS suggests that you follow the IETF-recommended mitigation method of binding the CSRF token to the user’s authenticated state (using, for example, a the hash of a session cookie).

Note: Sensitive strings (such as sessionCookie) can be used directly as the csrfToken in the Token SDK since it hashes the token before using it. For more details on CSRF attacks against OAuth 2.0 and mitigation techniques, refer to this rfc.

If your application does not have user authentication, you can use Util.generateNonce to generate a secure random string to use as a CSRF token.
state Developer-specified string that allows state to be persisted between the the request and callback phases of the flow.

Important Note: The state parameter can contain additional application-specific information, but should not be used to authenticate a user. The authentication must be performed prior to the initiation of the Smart Token Request Flow, and the callback should use the same authenticated session.


Pass the state and csrfToken parameters into the generateTokenRequestUrl method in Step 2.

requestId ID of the TokenRequest to be used for this request. Refer here for how to create a TokenRequest.

Example of using generateTokenRequestUrl with a CSRF token

const tokenRequestUrl = Token.generateTokenRequestUrl(requestId, state, csrfToken);
String tokenRequestUrl = tokenClient.generateTokenRequestUrlBlocking(
        requestId,
        state,
        csrfToken);
string tokenRequestUrl = tokenClient.GenerateTokenRequestUrl(
        requestId,
        state,
        csrfToken
        .Result;


Retrieve the state when parsing the callback url in Step 3 by passing in the same csrfToken.

callbackUrl The callback URL of your backend-service, along with query parameters
tokenId ID of requested token. Can be redeemed for information or payment initiation.

Example of using parseTokenRequestCallbackUrl with a CSRF token

parseTokenRequestCallbackUrl(callbackUrl, csrfToken).then(function(res) {
        const tokenId = res.tokenId;
        const state = res.innerState;
})
TokenRequestCallback callbackParams = tokenClient.parseTokenRequestCallbackUrlBlocking(
        callbackUrl,
        csrfToken);

String tokenId = callbackParams.getTokenId();
String state = callbackParams.getState();
TokenRequestCallback callbackParams = tokenClient.ParseTokenRequestCallbackUrl(
        callbackUrl,
        csrfToken)
        .Result;

string tokenId = callbackParams.TokenId;
string state = callbackParams.State;

Frequently Asked Questions

Do I need to have an AISP (account information service provider) or PISP (payment initiation service provider) license to use your service?

No, Token has obtained AISP and PISP approval by the FCA in the UK and passported across Europe. Please note than if you require AIS functionality you may be required to be registered as an agent of Token via the FCA. We will assist you with any required formalities please contact us for further information.

Do you have a sandbox that I can test with?

Yes, Token has a full sandbox with model banks for you to test your integration against. In the initial setup steps, point your SDK client to connect to our SANDBOX environment. We recommend you start out with Wood Bank (United Kingdom), contact us to learn more about the other banks we have available.

Can I test against sandboxes hosted by real banks in your network?

When you have completed your integration and have successfully tested against Token’s model banks, you will be able to test with one of the directly integrated partner banks (pursuant to PSD2 regulations). For more details don’t hesitate to contact us.

Can I set up a standing order or recurring payment using your Smart Token technology?

While our technology is capable of this, the banks in our network currently only support single immediate payments. Standing orders, future dated payments, and additional payment options will be delivered during 2019.

Does Token offer categorization options for retrieving transaction history?

Token does not currently offer categorization, we expect to offer this service in the future.

Can I make cross-border payments?

The banks in our network currently only offer domestic payments; banks in select regions in our network are expected to support this later in 2019. As such, UK banks only support GBP payments, and EU banks only support EUR payments. Token uses underlying bank rails to initiate payments, the initiating bank determines the most suitable rail to use given the payment details.

How do I notify Token of questions or issues I’m encountering?

Contact Us at our support desk, and we’ll get back to you as soon as we can.

Copyright © 2018 Token, Inc. All Rights Reserved