API Integration of BioGovID: TrustStamp

Overview

This guide will show you how to use the AXN Verify API to verify an individual via. TrustStamp.

๐Ÿ“˜

Prerequisites

  • Deploy the "TrustStamp" Workflow by following the directions here.
  • Obtain the access keys for your new workflow by following the directions here
  • Download and use the TrustStamp Postman Project to try it out

What you'll do:

  • Create a dropdown on your user interface to allow the end user to select whether to send link via Email or Text Message (Step 2).
  • Specify the redirect page your users return to.
  • Brand your Truststamp workflow.

Branding

๐Ÿ“˜

Truststamp offers you the ability to brand your end user interface. To brand your interface, visit the link below to download Truststamp's branding template:

https://stg.orchestration.truststamp.net/docs/v2/flow/configuration/?h=branding#branding-configuration-example

Once downloaded & customized, follow these instructions to update your template in IDDataWeb:

  1. Go to Verification Services > "your-verification-service"
  2. From the dropdown, click Start Change Request.
  3. Inside your service, go to Services > Properties. Then, add your template to the field asyncUIBranding

  1. Click Save & Close, then deploy.

Redirect URL

๐Ÿ“˜

After completing document capture, your users will need to be properly redirected away from your Truststamp interface.

The redirect page they return to is specified by the field asyncUIRedirect.

1. Get Access Token

(POST) https://api.preprod.iddataweb.com/v1/token

API Reference: https://docs.iddataweb.com/reference/auth

This access token is used to authenticate your requests. Place this token in the header of each subsequent request. See the postman project above for examples.

Locate your workflow's access keys


Then, to request an access token:


var axios = require('axios')

var user = 'Your Workflow API Key';
var password = 'Your Workflow Shared Secret';

var base64encodedData = Buffer.from(user + ':' + password).toString('base64');

var request = async () => {
  var response = await axios({
    url: 'https://api.preprod.iddataweb.com/v1/token',
    method: 'post',
    params: {
      grant_type: 'client_credentials'
    },
    headers: {
      'Content-Type': 'application/json',
      'Cache-Control': 'no-cache',
      Authorization: 'Basic ' + base64encodedData
    }
  })
  console.log(response.data);
}
request();

Response


{
    "errorCode": "",
    "errorDescription": "",
    "access_token": "TjZK7NSjw24AxGK9UhOE9uJDaZT23gKYuUC-9GMTAgLU", // your access token
    "expires_in": "1800",
    "token_type": "Bearer"
}

2. Get / Send TrustStamp Link

(POST) https://api.preprod.iddataweb.com/v1/async-ui/send-link
& (POST) https://api.preprod.iddataweb.com/v1/async-ui/get-link

API Reference: https://docs.iddataweb.com/reference/slverify

Once you've received an access token, you'll use it to send a TrustStamp Capture link to your end user.

Using the same API Key as before, prompt the user to select whether to send the link via Email or Text Message. Then, using their selection, make the appropriate request.

๐Ÿ‘

TIP:

You can optionally generate a link and not have it sent to your end user automatically. That way, you can control how this link is provided. See /get-link

To generate and deliver the link automatically, see /send-link


Request: /send-link


var data = {
    "apikey": "Your API Key",
    "credential": "e.g. : [email protected]",
    "appID":"Your App Name, (e.g. 'Employee Onboarding App')", 
    "country": "US",
    "userAttributes": [
/** -- Only include one of the below options as "userAttributes": [] -- **/

// Option 1: Send Capture Link via. Text Message
// --- start option: 1 ---
      {
          "attributeType": "InternationalTelephone",
          "values": {
          	"dialCode": "1",
          	"telephone": "1234567890"
          }
      },
// --- end option: 1 ---
// Option 2: Send Capture Link via. Email
// --- start option: 2 ---
      {
          "attributeType": "Email",
          "values": {
            "email": "[email protected]"
          }
      },
// --- end option: 2 ---
      
 
//You can optionally include additional customer PII as attributes (inside userAttributes)  using the following format:
  
      
      {
            "attributeType": "InternationalTelephone",
            "values": {
                "dialCode": "1",
                "telephone": "0000000000"
            }
        },
      {
            "attributeType": "FullName",
            "values": {
                "fname": "",
                "mname": "",
                "lname": ""
            }
      }
// for the list of all accepted attributes, visit: https://docs.iddataweb.com/reference/overview-2
    ]
 
}

var axios = require('axios')
var token = 'YOUR_BEARER_TOKEN' // -- obtained from step 1 --

var request = async () => {
  var response = await axios({
    url: 'https://api.preprod.iddataweb.com/v1/async-ui/send-link',
    method: 'post',
    data: data,
    headers: {
      'Content-Type': 'application/json',
      'Cache-Control': 'no-cache',
      Authorization: 'Bearer ' + token,
    }
  })
	console.log(response.data)
}
request();


Request: /get-link

var data = {
    "apikey": "Your API Key",
    "credential": "e.g. : [email protected]",
    "appID":"Your App Name, (e.g. 'Employee Onboarding App')", 
    "country": "US",
    "userAttributes": [] // Note: for /get-link, userAttributes (e.g. email, telephone) are not required,
												//  because no link is sent via text,  your response is the link. 
}

var axios = require('axios')
var token = 'YOUR_BEARER_TOKEN' // -- obtained from step 1 --

var request = async () => {
  var response = await axios({
    url: 'https://api.preprod.iddataweb.com/v1/async-ui/get-link',
    method: 'post',
    data: data,
    headers: {
      'Content-Type': 'application/json',
      'Cache-Control': 'no-cache',
      Authorization: 'Bearer ' + token,
    }
  })
	console.log(response.data)
}
request();

Response


/** Depending on the endpoint used  **/

// Response: to  /send-link
{ 
    "services": [
        {
            "name": "TrustStamp BioGovID Verification",

             // Creates and delivers link.
            "status": "delivered",

            "apSessionId": "34523008-c5a3-4ca0-93452-2z5mbd10"
        }
    ],
    "asi": "4e234574e8-c706-45eb-b648-effdb90ff31a7"
}

// Response: to  /get-link
{
    "services": [
        {
            "name": "TrustStamp BioGovID Verification",

            // Returns link instead of delivering it.
            "url": "https://stg.orchestration.truststamp.net?session_id=9qeZvvG&lang=en",

            "status": "initialized",
            "apSessionId": "c5af5e18-bbff-479f-b721-09b3ce06e754"
        }
    ],
    "asi": "3dc24510-c44b-4000-849d-cf7644685aad"
}

3. Verify

(POST) https://api.preprod.iddataweb.com/v1/slverify

API Reference: https://docs.iddataweb.com/reference/slverify

Lastly, you'll collect the asi (obtained from step 2) and submit it to the endpoint /slverify for a final policy decision.

๐Ÿšง

IMPORTANT:

When your user completes verification at Truststamp, they will be redirected to the Redirect URL you have specified, along with the ASI for their completed user session.

Example: https://www.iddataweb.com/redirect/?asi=6cd23a78-cd52-28e7-sdae-009c3234bb

In your application, expose one /GET endpoint to receive and verify completed user sessions.

Request

const axios = require("axios"); // http-request library

app.get("/redirect", async (request, response) => {
    // Retrieve the ASI obtained from your redirect URL.
    var asi = req.query.asi

    // Slverify payload:
    var data = {
        "credential": "truststamp",
        "asi": "your_transaction_ID", // -- obtained from step 2 --
        "appID": "",
        "userAttributes": [],
        "country": "US",
        "idpType": "optional idp type",
        "apikey": "Your API Key"
    }

    var token = 'YOUR_BEARER_TOKEN'; // -- obtained from step 1 --

    var request = async () => {
        var response = await axios({
            url: "https://api.preprod.iddataweb.com/v1/slverify",
            method: "post",
            body: data,
            headers: {
                "Content-Type": "application/json",
                "Cache-Control": "no-cache",
                Authorization: "Bearer " + token,
            },
        });
        return response.data
    };

    // Lastly, call slverify to receive your user's policy decision.
    var policyDecision = await request().policyDecision;

    // Redirect your user depending on their result.
    if (policyDecision === 'approve') {
        // ... grant the user access
        response.redirect(`https://www...com/approved`)
    }

    if (policyDecision === 'deny') {
        // ... deny the user access
        response.redirect(`https://www...com/denied`)
    }
})

Response


{
    "errorCode": "",
    "errorDescription": "",
    "transaction_id": "76gjhbl9-842c-4d2f-8d43-13c5fb4eff23",
    "userAttributes": null,
    "acquiredAttributes": [
        {
            "provider": "TrustStamp",
            "serviceOffering": "TrustStamp BioGovID Verification",
            "attributeType": "SubmissionTimestamp",
            "dateCreated": "08/17/2023 18:22:41",
            "values": {
                "Timestamp": "17/08/2023 18:22:41"
            }
        },
        {
            "provider": "TrustStamp",
            "serviceOffering": "TrustStamp BioGovID Verification",
            "attributeType": "WorkflowTransactionStageAttempt",
            "dateCreated": "08/17/2023 18:22:41",
            "values": {
                "Count": "1"
            }
        },
        {
            "provider": "TrustStamp",
            "serviceOffering": "TrustStamp BioGovID Verification",
            "attributeType": "WorkflowTransactionStage",
            "dateCreated": "08/17/2023 18:22:41",
            "values": {
                "Stage": "1"
            }
        }
    ],
    "userAssertionList": [
        {
            "provider": "TrustStamp",
            "serviceOffering": "TrustStamp BioGovID Verification",
            "dateAsserted": "02/13/2024 20:41:41",
            "assertions": {
                "test.overallDocumentCrosscheck": "pass",
                "test.2DBarcodeContentCheck": "pass",
                "test.driversLicenseBarcodeVerified": "pass",
                "test.documentAuthenticated": "pass",
                "test.selfieLiveness": "pass",
                "test.selfiePhotoIntegrityVerified": "pass",
                "link.fullName_driversLicense": "pass",
                "test.overallSelfieLivenessVerified": "pass",
                "link.selfie_govID": "pass"
            }
        }
    ],,
    "mbun": "jvsdahv87876-20a1-4bbc-925b-6ffeb7619ea3",
    "forwardApiKey": "",
    "policyObligation": false,
    "policyDecision": "approve"
}

If the policyDecision = approve , the user has been approved. Additional information on the SLVerify output(s) can be found here.

TrustStamp Assertions

The following table describes each assertion evaluated during TrustStamp Document Verification.

AssertionDescription
link.selfie_govIDHighest order / compound assertion which ensures all of the assertions below are PASS:

- test.documentAuthenticated
- test.facialPhotosMatch
test.2DBarcodeContentCheckChecks to ensure 2d barcode was extracted correctly
test.documentAuthenticatedA check which ensures the identified document type is a valid, unmodified Government-issued identification card.
test.driversLicenseBarcodeVerifiedThe subject's Driver's License barcode has been verified by TrustStamp
test.overallSelfieLivenessVerifiedA direct mapping (pass / fail) to TrustStampโ€™s: "liveness_verdict": boolean (true / false)
test.selfieLivenessEnsures the selfie taken is of a live face (not a picture-of-picture, printed paper or a mask)
test.selfiePhotoIntegrityVerifiedEnsures the selfie taken has maintained its original integrity and has not been tampered with programmatically or by other means
link.fullName_driversLicenseChecks if the full name provided matches the full name on the document (fuzzy match available).

Note: We can match first name, multiple first names, and first-part of multiple first name

ex. Bobby-Joe Aiken can match as Bobby Aiken or Bobby-Joe Aiken.