API Integration of KBA

Overview

This guide will show you how to use the AXN Verify API to verify an individual by Knowledge Based Authentication (KBA).

📘

Prerequisites

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

📘

An example KBA application is also made available for you to download here

What you'll do:

  • Collect the Full Name, Home Address and Date of Birth of the end user.
  • Using the user's personal information (PII), generate a dynamic set of Questions for the user to answer in order to prove their identity.
  • Validate the answers provided and determine if the end user is who they claim to be.

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": "TjZK7NSjw45AxGK9UhOE9uJDaZT23gKYuUC-9GMTAgLU", // your access token
    "expires_in": "1800",
    "token_type": "Bearer"
}

1.1. Country Selection

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

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

Once you've received an access token, you'll need to check if the user is located in a country supported by our services.

Using the same API Key as before, prompt the user to select a country, and if the country is supported, your response will contain the API Key required to take the next step in MobileMatch verification.


Request


var data = {
	"apikey": "Your API Key",
    "credential": "e.g. : [email protected]",
    "appID":"Your App Name, (e.g. 'Employee Onboarding App')",
    "userAttributes": [
        {
            "attributeType": "Country",
            "values": {
                "country": "US" // accepted values: (country codes) e.g. "US", "MX", "AU" ....
            }
        }
    ]
}

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/slverify',
    method: 'post',
    data: data,
    headers: {
      'Content-Type': 'application/json',
      'Cache-Control': 'no-cache',
      Authorization: 'Bearer ' + token,
    }
  })
	console.log(response.data)
}
request();

Response


{
    "errorCode": "",
    "errorDescription": "",
    "transaction_id": "xxxxx-xxxx-xxxx-xxxx-xxxxx",
    "userAttributes": [
        {
            "attributeType": "Country",
            "dateCreated": "11/08/2022 17:26:36",
            "values": {
                "country": "US"
            }
        }
    ],
    "acquiredAttributes": null,
    "userAssertionList": [
        {
            "provider": "Threatmetrix",
            "serviceOffering": "Threatmetrix Session Query Low Location Accuracy",
            "dateAsserted": "11/08/2022 17:26:37",
            "assertions": {
                "blacklist.device": "unverified",
                "blacklist.ofacIP": "unverified",
                "test.gte3Credential1d": "unverified",
                "detect.browserAnomaly": "unverified",
                "test.gte5Credential1d": "unverified",
                "test.lte3ProxyToday": "unverified",
                "test.trustedDevice6mo": "unverified",
                "test.trustedDevice": "unverified",
                "detect.possibleVPNOrTunnel": "unverified",
                "test.lte3CredentialsDevice7d": "unverified",
                "test.gte5Device1d": "unverified",
                "link.timeZone_TrueGeo": "unverified",
                "test.gte5CredentialDevice1d": "unverified",
                "test.credentialLTE500mi1hr": "unverified",
                "detect.vpn": "unverified",
                "test.exactIDAgeGTE7d": "unverified",
                "test.trueIPLTE500miInputIP": "unverified",
                "detect.proxyAnonymous": "unverified",
                "test.apSessionIDNotReplay": "unverified",
                "detect.jailbreak": "unverified",
                "link.proxyOrg_TrueOrg": "unverified",
                "test.expectedLanguage": "unverified",
                "blacklist.ip": "unverified",
                "detect.malware": "unverified",
                "detect.torExitNode90d": "unverified",
                "test.gte10Credential1d": "unverified",
                "detect.mobileTethering": "unverified",
                "test.trustedDevice28days": "unverified",
                "test.gte20Credential1d": "unverified",
                "detect.aggregator": "unverified",
                "test.smartIDAgeGTE7d": "unverified",
                "detect.proxyOpenTransparent": "unverified",
                "detect.unusualActivity": "unverified",
                "detect.proxyHidden": "unverified",
                "link.proxyISP_TrueISP": "unverified",
                "detect.tor": "unverified",
                "detect.torNode": "unverified",
                "detect.knownVPNISP": "unverified",
                "link.proxyGeo_TrueGeo": "unverified",
                "test.gte2Credential1d": "unverified"
            }
        }
    ],
    "mbun": "xxxxxx-xxxx-xxxx-xxxx-xxxxxx",
    "forwardApiKey": "324e1d4975f40c5", // your Dynamic KBA api key
    "policyObligation": true,
    "policyDecision": "obligation"
}

📘

NOTE:

The output above includes additional information from our Device Profiling service.

Device Profiling is the process of screening the Device and User Activity of a new transaction (user session).

If a transaction is found to be high risk (fraud), you'll be alerted of any fraudulent activity found, and the transaction will be prevented from proceeding further. Device Profiling requires an embedded script to run. Without it, assertions will be marked "unverified".

For more information on Device Profiling

2. Collect Personal Information (PII) / Get KBA Questions

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

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

The endpoint /kba/config collects the personal information (PII) of the user, and responds with specific questions for the end user to answer.

Tip

  • Your application should show form fields which allow the user to submit their Name, Address and Date of Birth. Once the user clicks submit, your application should collect and submit their personal information to /kba/config. Your UI should then render the next step: a multiple choice quiz, covered in step 3.

👍

Each step has a designated API Key.

Each key is designed to return the API key required for the next step. This key is called your forwardApiKey.

In the response body of your last request, you'll find your next forwardApiKey.


Request


var data = {
    "apikey": "YOUR_KBA_API_KEY", // -- obtained from step 1.1 -- 
    "credential": "[email protected]",
    "appID":"YOUR_APPLICATION_NAME",
    "asi": "xxxxx-xxxx-xxxx-xxxx-xxxxx", // -- obtained from step 1.1 --
    "userAttributes": [
        {
            "attributeType": "FullName",
            "values": {
                "fname": "John",
                "mname": "",
                "lname": "Smith"
            }
        },
        {
            "attributeType": "InternationalAddress",
            "values": {
                "country": "US",
                "administrative_area_level_1": "CA",
                "locality": "Vienna",
                "postal_code": "12345",
                "route": "May Street Town",
                "street_number": "1234"
            }
        },
        {
            "attributeType": "DOB",
            "values": {
                "day": "10",
                "month": "01",
                "year": "1985"
            }
        }
        
    ]
}

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

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

Where kbaQuestions.QuestionSet.Questions is a set of Personal Questions intended to verify whether the individual is who they say they are.

Response


{
    "hasNext": false,
    "asi": "xxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxx",
    "errorCode": null,
    "status": "success",
    "message": null,
    "userAttributes": null,
    "acquiredAttributes": [
        {
            "provider": "Lexis Nexis",
            "serviceOffering": "LexisNexis KBA",
            "attributeType": "LexID",
            "dateCreated": "09/08/2022 12:55:04",
            "values": {
                "lexID": "Not Provided"
            }
        }
    ],
    "userAssertionList": [
        {
            "provider": "Lexis Nexis",
            "serviceOffering": "LexisNexis KBA",
            "dateAsserted": "09/08/2022 12:55:04",
            "assertions": {
                "test.velocity": "pass",
                "test.discovery": "pass",
                "test.KnowledgeBasedAuthentication": "unverified"
            }
        }
    ],
    "kbaQuestions": {
        "ConversationId": "31017794510665",
        "QuestionSet": {
            "QuestionSetId": 5169006631,
            "Questions": [
                {
                    "QuestionId": 14652579931,
                    "Key": 1010,
                    "Type": "singlechoice",
                    "Text": {
                        "Statement": "Which of the following addresses have you ever been associated with?"
                    },
                    "HelpText": {
                        "Statement": "The addresses listed may be partial, misspelled or contain minor numbering variations from your actual address"
                    },
                    "Choices": [
                        {
                            "ChoiceId": "79228485321",
                            "Text": {
                                "Statement": "11431 147th Street"
                            }
                        },
                        {
                            "ChoiceId": "79428485331",
                            "Text": {
                                "Statement": "123 Pinewood Street"
                            }
                        },
                        {
                            "ChoiceId": "79228285341",
                            "Text": {
                                "Statement": "208 East Dean Street"
                            }
                        },
                        {
                            "ChoiceId": "79228585351",
                            "Text": {
                                "Statement": "26 Mountainview Avenue"
                            }
                        },
                        {
                            "ChoiceId": "79228685361",
                            "Text": {
                                "Statement": "I have never been associated with any of these addresses"
                            }
                        }
                    ]
                },
                {
                    "QuestionId": 14632879941,
                    "Key": 1020,
                    "Type": "singlechoice",
                    "Text": {
                        "Statement": "Which of the following street addresses in Schenectady have you ever lived at or been associated with?"
                    },
                    "HelpText": {
                        "Statement": "The addresses listed may be partial, misspelled or contain minor numbering variations from your actual address"
                    },
                    "Choices": [
                        {
                            "ChoiceId": "79228385371",
                            "Text": {
                                "Statement": "12 Main Street"
                            }
                        },
                        {
                            "ChoiceId": "79226485381",
                            "Text": {
                                "Statement": "1863 Foster Avenue"
                            }
                        },
                        {
                            "ChoiceId": "79228475391",
                            "Text": {
                                "Statement": "205 Morris Road"
                            }
                        },
                        {
                            "ChoiceId": "79528485401",
                            "Text": {
                                "Statement": "215 Shereen Court"
                            }
                        },
                        {
                            "ChoiceId": "79328485411",
                            "Text": {
                                "Statement": "None of the above or I am not familiar with this property"
                            }
                        }
                    ]
                },
                {
                    "QuestionId": 14652879951,
                    "Key": 5401,
                    "Type": "singlechoice",
                    "Text": {
                        "Statement": "Which of the following colleges have you attended?"
                    },
                    "HelpText": {
                        "Statement": "Select the college you have attended."
                    },
                    "Choices": [
                        {
                            "ChoiceId": "79224485421",
                            "Text": {
                                "Statement": "Allan Hancock College"
                            }
                        },
                        {
                            "ChoiceId": "79228685431",
                            "Text": {
                                "Statement": "Cuesta College"
                            }
                        },
                        {
                            "ChoiceId": "79228485441",
                            "Text": {
                                "Statement": "Emory University"
                            }
                        },
                        {
                            "ChoiceId": "79228475451",
                            "Text": {
                                "Statement": "St. Norbert College"
                            }
                        },
                        {
                            "ChoiceId": "79268485461",
                            "Text": {
                                "Statement": "None of the above"
                            }
                        }
                    ]
                }
            ]
        }
    }
}

3. Submit Answers

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

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

The user completes a multiple choice quiz. Once the user has finished answering each question, use the endpoint /kba/submit to submit their answers.

Tip

  • For the multiple choice quiz, show the questions on the screen from step 2, with radio buttons beside each option. The user should answer each of the 3 questions. Once they've selected their answers and clicked submit, call the endpoint /kba/submit.
  • The properties ConversationId, QuestionSetId, and QuestionId & Choice pairs will come from what you obtain from the response of Step 2.
  • For each question - map the QuestionId to the corresponding Choice to that which the end user has selected. For example: QuestionId: 15396189581, the user's answer was Choice: "83112910541".

Request


var data = {
  "asi": "xxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxx", // -- obtained from step 1.1 --
  "apikey": "YOUR_KBA_API_KEY", // -- obtained from step 1.1 --
  "appID": "YOUR_APPLICATION_NAME",
  "credential": "[email protected]",
  "kbaRequest": {
    "ConversationId": "31018778535695",
    "Answers": {
      "QuestionSetId": "5416349861",
      "Questions": [
        {
          "QuestionId": 15396189581,
          "Choices": [
            {
              "Choice": "83112910541",
            },
          ],
        },
        {
          "QuestionId": 15396189601,
          "Choices": [
            {
              "Choice": "83112910711",
            },
          ],
        },
        {
          "QuestionId": 15396189621,
          "Choices": [
            {
              "Choice": "83112910851",
            },
          ],
        },
      ],
    },
  },
};

var axios = require("axios");
var token = "YOUR_BEARER_TOKEN"; // -- see step 1 --

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

Response


{
    "hasNext": false,
    "asi": "xxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxx",
    "errorCode": null,
    "status": "success",
    "message": null,
    "userAttributes": null,
    "acquiredAttributes": null,
    "userAssertionList": [
        {
            "provider": "Lexis Nexis",
            "serviceOffering": "LexisNexis KBA",
            "dateAsserted": "09/08/2022 13:09:48",
            "assertions": {
                "test.KnowledgeBasedAuthentication": "pass"
            }
        }
    ],
    "kbaQuestions": null
}

Retry

If your user fails to answer correctly, and your service is configured to allow for retries, your response from /submit will be as follows:

{
    "hasNext": true, < ---  This indicates the user is eligbile to retry.
    "asi": "xxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxx",
    "errorCode": null,
    "status": "success",
    "message": null,
    "userAttributes": null,
    "acquiredAttributes": null,
    "userAssertionList": [
        {
            "provider": "Lexis Nexis",
            "serviceOffering": "LexisNexis KBA",
            "dateAsserted": "09/08/2022 13:09:48",
            "assertions": {
                "test.KnowledgeBasedAuthentication": "fail" < --- Result of failed KBA attempt.
            }
        }
    ],
    "kbaQuestions": null
}

if hasNext is true, resubmit /config (step 2) to generate a new question set.

🚧

NOTE:

Make sure to reference the same ASI or transaction ID in your second /config request.

Repeat steps 2 and 3 until hasNext is false.

4. Verify

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

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

In this step, you submit the transaction ID and PII of the individual to /slverify to retrieve a final policy decision.

Tip

  • This endpoint should be called immediately after receiving a response from Step 2. At this point, your app should be "verifying..." the information received, as the response of this next request will be the final policy decision.

Request


var data = {
  "asi": "xxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxx", // -- obtained from step 1.1 --
  "apikey": "YOUR_KBA_API_KEY", // -- obtained from step 1.1 --
  "credential": "[email protected]",
  "appID":"ID DataWeb",
  "userAttributes": [
       {
          "attributeType": "FullName",
          "values": {
              "fname": "John",
              "mname": "Miller",
              "lname": ""
          }
      },
      {
          "attributeType": "InternationalAddress",
          "values": {
              "country": "US",
              "administrative_area_level_1": "VA",
              "locality": "Vienna",
              "postal_code": "12345",
              "route": "Library Street",
              "street_number": "123"
          }
      },
      {
          "attributeType": "DOB",
          "values": {
              "day": "01",
              "month": "01",
              "year": "1985"
          }
      }
      
  ]
}

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/slverify",
    method: 'post',
    data: data,
    headers: {
      "Content-Type": "application/json",
      "Cache-Control": "no-cache",
      Authorization: "Bearer " + token,
    },
  });
  console.log(response.data);
};
request();

Response


{
    "errorCode": "",
    "errorDescription": "",
    "transaction_id": "xxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxx",
    "userAttributes": [
        {
            "attributeType": "FullName",
            "dateCreated": "10/28/2022 13:16:09",
            "values": {
                "fname": "John",
                "lname": "Smith",
                "mname": "",
                "suffix": null
            }
        },
        {
            "attributeType": "InternationalAddress",
            "dateCreated": "09/08/2022 13:16:09",
            "values": {
                "country": "US",
                "sublocality": null,
                "locality": "Vienna",
                "subpremise": null,
                "sublocality_level_2": null,
                "route": "library street",
                "administrative_area_level_2": null,
                "premise": null,
                "sublocality_level_5": null,
                "administrative_area_level_3": null,
                "sublocality_level_4": null,
                "sublocality_level_3": null,
                "administrative_area_level_1": "VA",
                "street_number": "123",
                "neighborhood": null,
                "postal_code": "12345"
            }
        },
        {
            "attributeType": "DOB",
            "dateCreated": "09/08/2022 13:16:09",
            "values": {
                "month": "01",
                "year": "1985",
                "day": "01"
            }
        }
    ],
    "acquiredAttributes": [
        {
            "provider": "IDDataWeb",
            "serviceOffering": "Assertion Score Service",
            "attributeType": "RawAssertionScore",
            "dateCreated": "09/08/2022 13:16:09",
            "values": {
                "rawAssertionScore": "3"
            }
        },
        {
            "provider": "IDDataWeb",
            "serviceOffering": "Assertion Score Service",
            "attributeType": "AssertionScore",
            "dateCreated": "09/08/2022 13:16:09",
            "values": {
                "assertionScore": "100"
            }
        },
        {
            "provider": "IDDataWeb",
            "serviceOffering": "IDDataWeb Trust Score Service",
            "attributeType": "IDWScore",
            "dateCreated": "09/08/2022 13:16:09",
            "values": {
                "idwScore": "100"
            }
        }
    ],
    "userAssertionList": [
        {
            "provider": "Lexis Nexis",
            "serviceOffering": "LexisNexis KBA",
            "dateAsserted": "09/08/2022 13:06:25",
            "assertions": {
                "test.velocity": "pass",
                "test.discovery": "pass",
                "test.KnowledgeBasedAuthentication": "pass"
            }
        }
    ],
    "mbun": "xxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxx",
    "forwardApiKey": "",
    "policyObligation": false,
    "policyDecision": "approve" // expect values: 'approve', 'deny'
}


Result

If policyDecision = approve, the individual has been approved.

policyDecision is a standard output of /slverify, the endpoint used to verify user information. Additional information on the output of SLVerify can be found here.

For instructions on how to test this workflow (including real user data), please visit: Testing Dynamic KBA Only