We thought we would play around with a bit of an idea for basic KYC integration in the crypto space by pinging account information from other exchanges. The first exchange we chose to explore was Coinbase, which is an exchange who does extensive KYC before users are allowed to most of its functionality.
The general idea is to grant our Coinbase app privileges to send 0.001 Ether to the users injected MetaMask browser address and view their basic Coinbase account details to ensure they are a verified user. This should not be used as the main KYC component in the platform, and is only a proof of concept that could potentially allow users certain features that are limited.
Such integration would ease the user registration process and allow it to be fractionally legally compliant (however, this is an assumption that needs clarification). The whole process is very similar to other applications that grant access to the user’s Facebook account information to complete registration. We feel it is unnecessary to make users re-enter their personal information if that can be accessible via other means.
Temp Token
When creating your Coinbase App, you will be required to give a url that the user will be redirected to once they have granted permissions to the application. Once you have created the Coinbase App, you will be given a Client ID and Client secret which is unique to your app, and is used for communicating with Coinbase.
Below is a non-secure way of dealing with this, and should only be used on your localhost when testing. You will notice as soon as the temporary has been sent back we grab the users base Ether account on the injected Metamask browser with Web3.
if(document.URL != 'http://127.0.0.1:3000/'){
var tempCode = document.URL.split('?code=').pop();
$.ajax({
type: "GET",
url: "http://127.0.0.1:3000/coinbase/initiateVerification",
data: {
tempCode: tempCode,
metamask : web3.eth.coinbase
},
success: function(data) {
jsonViewer(data);
}
});
};
Access Token
Before we can access any of the user’s details, we first need to convert the temp token into an access token.
initiateVerification: function (req, res){
options.url = urls.getCodeForAccess;
metamaskAddr = res.req.query.metamask;
var dataStringForAuthToken ='grant_type=authorization_code&code=X&client_id=X&client_secret=X&redirect_uri=http://127.0.0.1:3000/'
options.method = 'POST';
options.body = dataStringForAuthToken;
request(options, function(error, response, body){
if (!error && response.statusCode == 200) {
res.send(body);
var resultJson = JSON.parse(body);
}
}
);
};
ID verification
Now that we have an access token, let us query for a valid account. Coinbase does not directly allow access to check if an ID has been verified on their platform, due to obvious security reasons. However, there is a little hacky way around this by querying if the user has a bank account that allows withdrawals, as withdrawals require ID to be verified.
function getValidBank(_accessToken){
options.url = urls.valid_bank;
header.Authorization = 'Bearer ' + _accessToken;
options.headers = header;
options.method = 'GET';
request(options, function (error, response) {
var jsonResponse = JSON.parse(response.body)
var responseData = jsonResponse.data;
var responseDataLength = responseData.length;
var index;
for(index=0; index < responseDataLength; index++){
if(responseData[index].allow_withdraw){
getAccountID(_accessToken);
}
}
});
};
Request partial details
We want to ping the user’s Coinbase account ID and their primary Ether wallet ID. Thus, in case there is a request from legal authorities to hand over this data in the future, we could do so and the authorities could use it to request Coinbase for more information.
function getAccountID(_accessToken){
options.url = urls.user;
header.Authorization = 'Bearer ' + _accessToken;
options.headers = header;
options.method = 'GET';
request(options, function (error, response) {
var jsonResponse = JSON.parse(response.body);
var responseData = jsonResponse.data;
idAddrToken['accountID'] = responseData.id;
getEthWalletID(_accessToken);
});
};
function getEthWalletID(_accessToken){
header.Authorization = 'Bearer ' + _accessToken;
options.headers = header;
options.method = 'GET';
options.url = urls.accounts_for_Transaction;
request(options, function(error,response){
var jsonResponse = JSON.parse(response.body)
var responseData = jsonResponse.data;
var responseDataLength = responseData.length;
var index;
for(index=0; index < responseDataLength; index++){
if(responseData[index].name == 'ETH Wallet'){
idAddrToken['ethWalletId'] = responseData[index].id;
postTransactionToMetamask(_accessToken, responseData[index].id);
}
};
});
};
Post Transaction To Metmask
This function sends 0.001 Eth from the users main Ether wallet ID to their Metamask address.
function postTransactionToMetamask(_accessToken, _ethWalletId){
transactionHeader.Authorization = ‘Bearer ‘ + _accessToken;
options.headers = transactionHeader;
options.url = urls.accounts_for_Transaction + _ethWalletId + urls.transaction;
options.method = ‘POST’;
metaMaskSend.to = metamaskAddr;
options.body = JSON.stringify(metaMaskSend);
request(options, function(error, response){
var jsonResponse = JSON.parse(response.body)
var responseData = jsonResponse.data;
idAddrToken[‘metamaskAddr’] = metamaskAddr;
idAddrToken[‘verificationTxID’] = responseData.id;
getTransactionHashAfterPosted(_accessToken, _ethWalletId, responseData.id); //requires time delay of 12 seconds
});
}
Get Transaction Hash
To further have a line of defense against legal entities, we also grab the transaction hash, which validates that the transaction did take place, and ifa legal entity wish to they can contact Coinbase with this transaction hash and account ID to validate that the transaction has executed. This function requires a delay of typically 12 seconds before executed after the Ether has been sent from the user’s Coinbase Eth wallet to Metamask.
function getTransactionHashAfterPosted(_accessToken, _ethWalletId, _verificationTxID){
options.url = urls.accounts_for_Transaction + _ethWalletId + urls.transaction + '/' + _verificationTxID;
header.Authorization = 'Bearer ' + _accessToken;
options.headers = header;
options.method = 'GET';
request(options, function (error, response) {
var jsonResponse = JSON.parse(response.body)
var responseData = jsonResponse.data;
idAddrToken['verificationTxHash'] = jsonResponse.network.hash;
getAllUserDetails(_accessToken);
});
};
Get All User Details
By following this order of execution, we only ping the user’s personal information once they have passed all the previous queries. If they have passed, the information that they used for Coinbase validation will be used to create an account on the MyBit platform.
function getAllUserDetails(_accessToken){
options.url = urls.user;
header.Authorization = ‘Bearer ‘ + _accessToken;
options.headers = header;
options.method = ‘GET’;
request(options, function (error, response) {
var jsonResponse = JSON.parse(response.body);
var responseData = jsonResponse.data;
idAddrToken[‘name’] = responseData.name;
idAddrToken[‘profileLocation’] = responseData.profile_location;
idAddrToken[‘email’] = responseData.email;
idAddrToken[‘timeZone’] = responseData.time_zone;
idAddrToken[‘nativeCurrency’] = responseData.native_currency;
idAddrToken[‘countryCode’] = responseData.country.code;
idAddrToken[‘countryName’] = responseData.country.name;
revokeAccess(_accessToken);
});
};
Revoke Access Token
Once all of the previous functions have successfully executed and we have obtained the necessary information for a basic KYC validation, we revoke the Coinbase Apps access token. Meaning that we cannot ping the user’s account anymore.
function revokeAccess(_accessToken){
options.url = urls.revoke_access;
header.Authorization = 'Bearer ' + _accessToken;
options.headers = header;
options.method = 'POST';
options.data = 'token='+ _accessToken;
request(options, function (error, response, body) {
console.log('Revoked access');
});
};
Pros:
-Fast to implement
-No cost
-Well known exchange
Cons:
-Not real KYC
-Provably has no real legal stand point
The whole purpose of this POC is to create a basic KYC model for Blockchain companies, but should not be used for the primary KYC model. Overall, this was an enjoyable exploration that could potentially aid companies and even ourselves to some extent.
Resources Used:
coinbase App
web3
ajax
mongodb
Example Git Repo — Contains fully functional localhost web pack when using developer access tokens. If you wish to integrate this fully you need to apply to Coinbase for higher App limits, as 0.001 Eth is above the maximum allowed to send before granted higher limits. It is a bit backwards since you are allowed to send $1 of value, but $1 of Eth is below the minimum amount of Eth that coinbase allows to send.
Connor Howe, Blockchain Engineer @ Mybit
Follow us on our socials too!
https://twitter.com/MyBit_DApp?lang=en
https://www.facebook.com/MyBitDApp/
https://t.me/mybitio
https://medium.com/mybit-dapp
Learn more about KYC and how it works:
https://aicrypto.vip/what-is-kyc-how-does-it-work/