Private profiles / KYC

This guide explains how to request, validate, and use the attested data in your chatbot.

Users can have some of their data verified by a trusted third party (attestor). The attestor posts an attestation record to the Obyte DAG, this record serves as a proof for relying parties that a user was attested. The attested data itself can be either posted publicly by the attestor, or only a hash of this data is posted while the plaintext data is saved in the wallet of the attested user. In the latter case, the user can disclose the attested data to selected peers, for example to your bot.

This can be used to KYC your users prior to providing a service, see You may need it e.g. to comply with regulations or protect against fraud.

ICO bot already uses the attested private profiles in order to allow only verified users to invest and to collect their personal data. You can use its code as reference.

Requesting private profile

To request a private profile, send this message to the user:

[profile request](profile-request:first_name,last_name,dob,country,id_type)

The message will be displayed in the user's chat window as a clickable link, which allows him to select one of the profiles stored in his wallet and send it over to the peer (your chatbot).

The message includes the list of fields you require the user to disclose. Here is the full list of available fields:

  • first_name: first name

  • last_name: last name

  • dob: date of birth in YYYY-MM-DD format_

  • country: the country that issued the ID (2-letter ISO code)

  • us_state: US state (only if country=US)

  • personal_code: government issued personal code (not all countries)

  • id_number: government issued document ID (not all documents)

  • id_type: ID type

  • id_subtype: ID sub-type (not all attestations)

  • id_expiry: ID expires at (not all attestations)

  • id_issued_at: ID issued at (not all attestations)

You should point the user to your privacy policy before requesting sensitive personal data.

Receiving private profile

When a user sends you his private profile, you receive it in a chat message that includes:

[any text](profile:privateProfileJsonBase64)

where privateProfileJsonBase64 is a base64-encoded JSON of the private profile object. You can easily find the profile in an incoming message using regular expression:

let arrProfileMatches = text.match(/\(profile:(.+?)\)/);

Then, decode the profile using private_profile.js module in ocore:

const privateProfile = require('ocore/private_profile.js');
let privateProfileJsonBase64 = arrProfileMatches[1];
let objPrivateProfile = privateProfile.getPrivateProfileFromJsonBase64(privateProfileJsonBase64);

objPrivateProfile object has 3 fields:

objPrivateProfile {
unit: "...", // attestation unit
payload_hash: "...", // pointer to attestation payload in this unit
src_profile: object // attested fields

Next, you need to validate this object and extract information about the attested and attestor addresses:

privateProfile.parseAndValidatePrivateProfile(objPrivateProfile, function(err, address, attestor_address){

This function verifies that the provided profile matches the hash stored on the DAG by the attestor. It also returns the user's address address (hence you don't need to ask the user about his address, the profile is enough) and the attestor address attestor_address (make sure it is on the list of attestors you trust).

The src_profile field of objPrivateProfile contains an associative array of attested fields. But not all fields have to be disclosed by the user.

  • If a field is disclosed, the value of objPrivateProfile[field] is an array of two elements: the plaintext value of the field and blinding. Blinding is a random string generated by the attestor when creating the profile, it serves to protect the private data from brute force attacks (the profile data is too predictable and can be easily checked against known hashes).

  • If the field is not disclosed, the value of objPrivateProfile[field] is a hash of plaintext value and blinding.

To extract just the disclosed data and remove all the bindings, use

let assocPrivateData = privateProfile.parseSrcProfile(objPrivateProfile.src_profile);

To save the received private profile, call

privateProfile.savePrivateProfile(objPrivateProfile, address, attestor_address);

It will save the profile in the tables private_profiles and private_profile_fields, which you can later query to read the data.