Flutter - Device Intelligence Integration Guide

A Flutter plugin for Bureau's Device Intelligence product. It helps you understand your user’s unique hardware with their device data. It efficiently syncs the data in the background and processes them. The processed data can be used to generate a fingerprint id.

Integration Overview

  • Integrate Android SDK in your application
  • Call the API to query device information
Device Intelligence Flow

Device Intelligence Flow

  1. SessionKey and UserID is generated from client backend and sent to the SDK.
  2. Invoke the submit function in SDK to pass the data to Bureau backend.
  3. Upon successful transmission of the parameters, a callback is received in the SDK, based on the callback (Success/Failure) next steps can be taken.
  4. If the callback is successful, Invoke Bureau's backend API /v1/suppliers/device-fingerprint to fetch the results.
  5. Use the fingerprint and risk signals to allow, block or redirect the user to a desired flow.

Usage

Install the package

Install onetaplogin ^ 1.1.9  as a [dependency in your pubspec.yaml file]

Refer the below change log for the latest dependency.

Changelog

Initialise the SDK

// Import package
import 'package:onetaplogin/onetaplogin.dart';

// To use Device Intelligence as a standalone product	  
var status = await Onetaplogin.submitDeviceIntelligence(  
//Here the status returned is a string and contains the finger print sdk's success or failure message

          clientID,
          txnID,
          msisdn, env : "Sandbox");

Parameter Description

KeyDescriptionMandatory/Optional
client_idThe client id shared by Bureau.Mandatory
environmentEnvironment in which SDK is being used. The SDK is configured to call the production endpoint by default, to change it to sandbox set the parameter env : "Sandbox" while initialising the SDK.Mandatory
txnIDIdentifier to track a session, note we recommend you to generate it from your backend. This has to be unique for every request.Mandatory
msisdnIdentifier for a user, can be internal customer ID.Mandatory

The status object for the submitDeviceIntelligence method would be a Bureau's own custom class with the following properties.

  • isSuccess boolean to check the success of device intelligence.
  • errorMessage and errorCode to pinpoint errors in the case isSuccess is false and empty for 'true' cases.

Android Manifest changes

//Add the folowing call if targeting S+ devices
<activity>
android:exported="true"
</activity>

Serverside URL's

Serverside call to get details.

curl --location --request POST 'https://api.overwatch.stg.bureau.id/v1/suppliers/device-fingerprint' \
--header 'Authorization: Basic MzNiNxxxx2ItZGU2M==' \
--header 'Content-Type: application/json' \
--data-raw '{
    "sessionKey": "697bb2d6-xxxx-487f-xxxx-548d6a809360"
}'

curl --location --request POST 'https://api.overwatch.bureau.id/v1/suppliers/device-fingerprint' \
--header 'Authorization: Basic MzNiNxxxx2ItZGU2M==' \
--header 'Content-Type: application/json' \
--data-raw '{
    "sessionKey": "697bb2d6-xxxx-487f-xxxx-548d6a809360"
}'

Response

{
    "GPSLocation": {
        "city": "Madurai",
        "country": "India",
        "latitude": 9.961932591738853,
        "longitude": 78.12884837677319,
        "region": "Tamil Nadu"
    },
    "IP": "106.51.82.180",
    "IPLocation": {
        "city": "Bengaluru",
        "country": "India",
        "latitude": 12.97623,
        "longitude": 77.603287,
        "region": "Karnataka"
    },
    "IPSecurity": {
        "isCrawler": false,
        "isProxy": false,
        "isTor": false,
        "VPN": false,
        "threatLevel": "LOW"
    },
    "IPType": "v4",
    "OS": "android",
    "debuggable": true,
    "emulator": true,
    "fingerprint": "1e3f8831-a062-4b55-ad37-ee5f414f1941",
    "firstSeenDays": 188,
    "mockgps": false,
    "model": "M2006C3MII",
    "package": "com.prism.android.prismsampleapp",
    "rooted": true,
    "userId": "demo-session-shekh-prd-user-25677",
    "isAppTampered": null,
    "isAppCloned": false,
    "riskLevel": "HIGH",
    "totalUniqueUserId": 3,
    "remoteDesktop": false,
    "voiceCallDetected": false,
    "sessionId": "demo-session-shekh-dev-android-2023-5-30-fp-640-19",
    "confidenceScore": 100,
    "createdAt": 1686125656521,
    "riskLevel": "VERY_HIGH",
    "riskScore": 90.46
}

{
  "data": null,
  "errors": {
    "status": 401,
    "errorCode": "UNAUTHORIZED",
    "service": "Overwatch"
  },
  "message": "",
  "meta": {
    "length": 0,
    "took": 0,
    "total": 0
  }
}
{
  "error": {
    "code": 0,
    "description": "",
    "message": "Server encountered an error",
    "metadata": null,
    "referenceId": "86529a18-a5cb-4da9-91b0-8d04cdb9167e",
    "type": "INTERNAL_SERVER_ERROR"
  },
  "merchantId": "auth0|61dfxxxx0071be7021",
  "requestId": "c69d86f0-xxxx-4ef0-xxxx-e687d595a507",
  "statusCode": 500,
  "timestamp": 1657009043753
}
{
    "error": {
        "code": 422,
        "description": "Failed to find fingerprint for given session key",
        "message": "NO_RECORD_FOUND",
        "metadata": null,
        "referenceId": "",
        "type": "NO_RECORD_FOUND"
    },
    "merchantId": "auth0|61dfbbxxxx420071be7021",
    "requestId": "24e1aa7f-xxxx-404d-xxxx-5f8a0227e8f0",
    "statusCode": 422,
    "timestamp": 1658402132141
}
{
    "statusCode": 400,
    "error": {
        "code": 0,
        "type": "BAD_REQUEST",
        "message": "Session key is missing",
        "description": "request does not contain additionalData.sessionKey param in request",
        "referenceId": "24f94ae8-xxxx-48a4-xxxx-b25f99fb06d9",
        "metadata": null
    },
    "timestamp": 1658402143450,
    "merchantId": "auth0|61dfbbxxxx3420071be7021",
    "requestId": "66403193-xxxx-44bc-xxxx-14735a45dfeb"
}

Response Description

KeyDescription
GPSLocation(city, country, latitude, longitude, region)GPS Based location of the user, user's consent is required to be taken to get this details.
IPLocation(city, country, latitude, longitude, region)IP based location of the user.
IPIP address of the user.
VPNFlag to indicate if the IP being used by the user is a VPN. (Note the VPN within the IPSecurity JSON object should be used and not the one outside.
isCrawlerFlag to indicate if the IP being used by the user is associated with a crawler.
isProxyFlag to indicate if the IP being used by the user is a proxy.
isTorFlag to indicate if the IP being used by the user is of a Tor network.
threatLevelThe threat level associated with the IP. Possible values can be ["low", "medium", "high"]
IPTypeThe type of IP, ["v4", "v6"]
OSThe OS of the user's device.
debuggableFlag to indicate if the app is in debug mode.
emulatorFlag to indicate if the app is being run on an emulator
fingerprintA hash generated for the device, this identifier will be unique for a device.
firstSeenDaysThe number of days from which the device is identified on Bureau's network.
isAppClonedFlag to indicate if the app is cloned.
isAppTamperedFlag to indicate if the app is tampered.
mockgpsFlag to indicate if the user is spoofing their GPS location. This will need users permission for background location.
modelThe device model.
packageThe package name.
rootedFlag to indicate if the device is rooted.
remoteDesktopWhether a remote desktop is monitoring the session
voiceCallDetectedIndicates if a voice call was active when device data was gathered
sessionIdThe session identifier, that was used to invoke the SDK.
riskLevelRisk level of the user, calculated based on the flags that are exposed in the above sections. Possible values ["LOW", "MEDIUM", "HIGH"]
riskScoreAlternative scoring models incorporate the data that is essentially derived from the above raw signals.
userIdThe userID that was sent as part of the request body.
totalUniqueUserIdThe total number of unique usersIDs associated to the fingerprint.
confidenceScoreThe confidence score for the fingerprint that was generated.

Go live Checklist

  1. For determining the app tamper check, we would require your package name and signature hash code, kindly ensure this is shared before going live. The hash code can be obtained from PackageManager GET_SIGNING_CERTIFICATES signingInfo.signingCertificateHistory this will be a byte array.