(Deprecated) ComPilot Identity SDK
The ComPilot Identity SDK is written in Typescript and allows you to integrate customer verification into your application through a JavaScript interface.
The verification flow provides identity verification. There are three key principles to implementing the verification flow.
- You use the ComPilot SDK to allow customers to go through a KYC process with a KYC provider and share the information with your app.
- ComPilot verifies the retrieved data using the compliance rules defined in the ComPilot Dashboard, and uses a webhook to tell your app the customer was approved or denied.
- Based on the results from ComPilot, you can handle how your app should behave for that customer.
This is described in Customer experience and Integration.
There is also a know your business (KYB) flow for running KYB checks.
This page describes how to implement these flows in your app.
There are several example applications built using the ComPilot Identity SDK. You can use these as a basis for building your own applications.
Setup
Before developing with the ComPilot Identity SDK, you need to have configured at least one workflow as described in Workflows.
As part of the setup process, you need to get an API key, as described in Getting an API key. This key is used as API_KEY
in this document.
Back-end setup
As part of the setup, you have to do certain things on the back end of your app.
Get the access token using the Generate client access token endpoint. This has to be done from a secure server to avoid leaking
API_KEY
. For example, in JavaScript:const response = await fetch("https://api.compilot.ai/kyc/auth/access-token", {
body: JSON.stringify({
address, // the address of the wallet
blockchainNamespace, // optional , "eip155" by default, can be also "tezos" or "aptos"
}),
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${process.env.API_KEY}`,
},
method: "POST",
});
const { accessToken } = await response.json();Where
address
is the address of the customer's Web3 wallet andblockchainNamespace
is the namespace of the blockchain you use.The back end of your app needs to implement a way of passing this to the front end of your app.
Configure the webhooks to handle the data they will receive. For information about webhooks, see Webhooks.
noteThe structure of the validation result could vary, depending on the rules, but it will still have all the necessary flags to determine whether the customer meets the requirements so that your app can allow or deny access the customer.
If the customer is trying to perform an action that requires verification, check if they are verified in your records.
- If the customer is verified and on the allowed list, let them proceed to the action.
- If the customer is verified and on the blocked list, block them.
- If not verified, initiate the ComPilot Identity SDK data request as described in the following steps.
Installation
The ComPilot Identity SDK can be installed using yarn
.
yarn add @nexeraid/identity-sdk
Initialization
The ComPilot verification workflow requires customers to authenticate using their Web3 wallet. This has two benefits:
- You can link your customers' real-world identity with their Web3 wallets.
- Customers' wallets can automatically screened with an onchain screening tool connected to ComPilot.
At the end of verification, customers are issued reusable KYC reports that can be controlled using their Web3 wallets.
The following blockchains are supported.
- All EVM chains (such as Ethereum, and Base)
- Aptos
- Cardano
- Cosmos
- Polkadot
- Solana
- Starknet
- Tezos
See Web3 authentication for more information.
These examples use the signMessageAsync
method from wagmi
. Replace this with the signature function of the supported blockchain of your choice (as long as it takes string as input and returns string).
The front end of your app must implement a signer that can sign with a Web3 wallet address. On Ethereum, this can be implemented with using a library like
viem
orethers
, and then paired withwagmi
,web3auth
, or another compatible library.Instantiate the KYC client,
IdentityClient
.import { IdentityClient } from "@nexeraid/identity-sdk";
const IDENTITY_CLIENT = new IdentityClient();Configure the signing callback.
- EVM
- APTOS
- Cardano
- Cosmos
- Polkadot
- Starknet
- Tezos
// mandatory onSignPersonalData callback
IDENTITY_CLIENT.onSignMessage(async (data: { message: string }) => {
// make customer sign data with wallet, and return result
return await signMessageAsync({ message: data.message });
});// mandatory onSignPersonalData callback
IDENTITY_CLIENT.onSignMessage(async (data: { message: string }) => {
// make customer sign data with wallet, and return result
return await signWithAptos(data.message, wallet);
});// mandatory onSignPersonalData callback
IDENTITY_CLIENT.onSignMessage(async (data: { message: string }) => {
// make customer sign data with wallet, and return result
return await signWithCardano(data.message, wallet);
});// mandatory onSignPersonalData callback
IDENTITY_CLIENT.onSignMessage(async (data: { message: string }) => {
// make customer sign data with wallet, and return result
return await signWithCosmos(data.message, wallet);
});IDENTITY_CLIENT.onSignMessage(async (data: { message: string }) => {
if (!wallet?.address) {
return "";
}
return await signWithPolkadot(
data.message,
wallet?.address,
wallet?.injector,
);
});IDENTITY_CLIENT.onSignMessage(async (data: { message: string }) => {
return await signWithStarknet(
data.message,
wallet?.account as AccountInterface,
);
});// mandatory onSignPersonalData callback
IDENTITY_CLIENT.onSignMessage(async (data: { message: string }) => {
// make customer sign data with wallet, and return result
return await signWithTezos(data.message, wallet);
});Build the signing message and signature, which is needed to securely store KYC data in the customer's browser.
- EVM
- Aptos
- Cardano
- Cosmos
- Polkadot
- Solana
- Starknet
- Tezos
const signingMessage = IdentityClient.buildSignatureMessage(address);
const signature = await signMessageAsync({ message: signingMessage });Where
address
is the address of the customer's Web3 wallet. For compatibility reasons, it should be lower case.For more context, see here.
const signingMessage = IdentityClient.buildSignatureMessage(address);
const aptosMessage = {
address: true,
application: true,
chainId: true,
message,
nonce: Date.now().toLocaleString(),
};
const { signature } = await wallet.signMessage(aptosMessage);Where
address
is the address of the customer's Web3 wallet. For compatibility reasons, it should be lower case.For more context, see
useAptosWallet.tsx
.export const signWithCardano = async (
message: string,
wallet: WalletApi | undefined,
) => {
if (!wallet) {
throw new Error("signWithCardano called before wallet was connected");
}
const usedAddresses = await wallet.getUsedAddresses();
const userAddress = usedAddresses[0];
if (!userAddress) {
throw new Error("No user connected in wallet");
}
const hexMessage = Buffer.from(message).toString("hex");
// Note: this only works with this raw address and not the formatted version
const { signature } = await wallet.signData(userAddress, hexMessage);
return CardanoSignature.parse(signature);
};For more context, see
useCardanoWallet.ts
.export const signWithCosmos = async (
message: string,
wallet: Keplr | undefined,
) => {
// Ensure that Keplr is installed and available
if (!wallet) {
throw new Error("Wallet not connected");
}
const offlineSigner = wallet.getOfflineSigner(COSMOS_CHAIN_ID);
const accounts = await offlineSigner.getAccounts();
const cosmosAddress = accounts[0]?.address;
if (!cosmosAddress) {
throw new Error("Wallet not connected - cosmosAddress missing");
}
// Sign the message using Keplr
const signed = await wallet.signArbitrary(
COSMOS_CHAIN_ID,
cosmosAddress,
message, // Make sure SIGN_MSG is defined somewhere in your code
);
// Decode base64 signature to bytes
const signatureBytes = Uint8Array.from(atob(signed.signature), (c) =>
c.charCodeAt(0),
);
// Convert bytes to hexadecimal string
const signatureHex = Array.prototype.map
.call(signatureBytes, (x: number) => ("00" + x.toString(16)).slice(-2))
.join("");
// Return the signature
return CosmosSignature.parse(signatureHex);
};For more context, see
useCosmosWallet.ts
.const signingMessage = IdentityClient.buildSignatureMessage(address);
const signature =
injector.signer.signRaw &&
(await injector.signer.signRaw({
address: accountAddress,
data: messageU8a.toString(),
type: "bytes",
}));Where
address
is the address of the customer's Web3 wallet. For compatibility reasons, it should be lower case.For more context, see
usePolkadotWallet.tsx
.signMessageAsync={async (message: string) => {
const messageBytes = new TextEncoder().encode(message);
const signature = await signMessage(messageBytes);
return signature && Buffer.from(signature).toString("hex");
}}export const signWithStarknet = async (
message: string,
account: AccountInterface | undefined,
) => {
if (!account?.signer) {
throw new Error("signWithStarknet called before wallet was connected");
}
// Message must be hashed in order to be signed by starknet
const messageHash = hash
.starknetKeccak(message)
.toString(16)
.substring(0, 31);
const starknetMessage = {
types: {
Message: [{ name: "hash", type: "felt" }],
StarkNetDomain: [{ name: "name", type: "felt" }],
},
primaryType: "Message",
domain: {
name: "Auth Message",
},
message: {
hash: messageHash,
},
};
// This returns a tuple of two numbers (r,s)
const signature = (await account.signMessage(
starknetMessage,
)) as ArraySignatureType;
if (!signature[0] || !signature[1]) {
throw new Error("returned starknet signature is wrong format");
}
// It has to be formatted to a single string for the purpose of polygon id derivation
const formattedSignature =
"0x" +
BigInt(signature[0]).toString(16) +
BigInt(signature[1]).toString(16);
return StarknetSignature.parse(formattedSignature);
};For more context, see
useStarknetWallet.ts
.const signingMessage = IdentityClient.buildSignatureMessage(address);
const { signature } = await wallet.client.requestSignPayload({
signingType: SigningType.MICHELINE,
payload: payloadBytes,
});Where
address
is the address of the customer's Web3 wallet. For compatibility reasons, it should be lower case.For more context, see
useTezosWallet.tsx
.Get the access token from your back end, and store it in a variable called
accessToken
. For example:const accessToken = getAccessTokenFromYourServer();
Where
getAccessTokenFromYourServer()
is a function you create to get the access token from your server.Pass the authorization inputs to the
init
method.await IDENTITY_CLIENT.init({
accessToken: accessToken,
signature: signature,
signingMessage: signingMessage,
});
For more detailed examples, see init
examples.
Methods
Once the front end has been initialized you can use the following methods.
startVerification
to start a verification flow.startKYB
to start a KYB flow.getStoredCredentials
to get a copy of the stored credentials.getTxAuthSignature
to retrieve a signature from the ComPilot API to authorize a contract call for a gated smart contract.polygonIdRequest
to interact with Polygon ID.close
to close the Identity SDK.