Front-End
Overview
Your front-end serves as the interface for user interaction with the CoKeeps Hot Wallet, facilitating administrative and wallet actions. The CoKeeps Hot Wallet acts as the central component in the process flow, verifying user information and authentication with your back-end server before executing further actions.
To maintain security and prevent unauthorised access or data tampering, requests are channelled through the CoKeeps JavaScript SDK. This SDK orchestrates specific operations, such as message signing and encryption, leveraging a cryptographic key generated on the user's device during login with their raw credentials. Through this protocol, the signature ensures data integrity by detecting any tampering throughout the life-cycle of the data within the CoKeeps Hot Wallet system, while encryption shields content from view between the user and the CoKeeps Hot Wallet system. This approach is more secure than HMAC or token-based methods, as it prevents spoofing and verifies that messages originate from the intended user.
As all communication relies on cryptographic keys, and the authentication private key remains on the user's device, sensitive data such as raw credentials is never stored in the CoKeeps Hot Wallet system nor does it leave the user's device - only the authentication public key is utilised.
All communications with the CoKeeps Hot Wallet occur over TLS (Transport Layer Security) using HTTPS.
IMPORTANT
The security measures outlined above are contingent upon the integrity of your front-end platform and the security of the user's device. In the presence of malware such as key-loggers, raw credentials may be compromised, making them susceptible to spoofing attacks. Implementing Multi-Factor Authentication (MFA) on your front-end adds an extra layer of security to mitigate such risks.
Preparations
During the integration phase, you will receive the CoKeeps JavaScript SDK. Follow these steps to integrate it into your web application:
<script src="/cksdk-browser.js"></script>
Initialisation on Application Load
var CKSDK = null;
window.addEventListener('load', async () => {
CKSDK = window.CKSDK;
// setup
const params = {
hostSignPublicKey: "<hot_wallet_public_key>",
hostId: "cokeeps-hotwallet",
hostEndpoint: "<hot_wallet_https_endpoint>"
};
// Include this only if it is used for your administration.
params.scope = "admin";
CKSDK.auth.setup(params);
const secret = "<your_system_generated_unique_user_secret_session>";
// Load session if it exists. Refer to the Log In section.
if (await CKSDK.auth.load(params.hostSignPublicKey, secret)) {
if (await CKSDK.auth.connected()) {
// Connection successful
} else {
// Connection failure with CoKeeps Hot Wallet:
// - Account is blocked by your back-end verify endpoint
// - Invalid hot wallet public key
// - Invalid secret
}
}
await run();
});
function run() {
// Your application processes
}
Replace <hot_wallet_public_key>
, <hot_wallet_id>
, and <hot_wallet_https_endpoint>
with the provided values during integration.
The <your_system_generated_unique_user_secret_session>
represents a unique user device secret generated by your system for each user session. It is crucial for encryption salt to the SDK for persistence mode. Failing to provide the same secret value within the same user session will invalidate Hot Wallet authentication cryptography keys and result in connection failure.
To Log in
async function log_in() {
const username = "<identifiable_such_as_email>";
var password = "<user_input_credential_or_webauth_private_key_string>";
// An error will be thrown if any issues arise
await CKSDK.auth.login({ username, password });
password = null; // Prevent future accidental use or leakage
// Securely store session for persistence
const secret = "<your_system_generated_unique_user_secret_session>";
CKSDK.auth.store(secret);
// Additional login routines
}
The raw password
value passed to the SDK is not transmitted or stored. It is used to generate the hot wallet authentication cryptography key.
Logging Out
async function log_out() {
// An error will be thrown if any issues arise
await CKSDK.auth.logout();
// Additional logout routines
}
NodeJS Version
All methods available in the Browser SDK are also accessible in the NodeJS SDK, but the strategy for managing sessions differs.
You only need to use the NodeJS version if your front-end application does not support JavaScript, such as in mobile applications. In such cases, the NodeJS version acts as a proxy for your user's requests and functions exactly like the Browser SDK version.
Here's an example of how to use this version:
const sha256 = require('crypto-js/sha256');
const { CKSDK, CKWRAP } = require("<path_to>/cksdk-node.min.js");
// Setup parameters
const setupParams = {
hostSignPublicKey: "<hot_wallet_public_key>",
hostId: "cokeeps-hotwallet",
hostEndpoint: "<hot_wallet_https_endpoint>"
};
// Let's assume this is your database
// 1. You should clear the uid session when the user logs out or when they reset their password
// 2. Session should have expiry if inactive for a period of time
const simpleSessionDatabase = {};
// A secret that should be isolated from other system
const serverSecret = "<your_system_secret_separated_from_database>";
// Example of a request function by a user
async function request(uid, sealed = false) {
// This must be within a request, not a global variable object
const CKUSER = CKWRAP.feed(CKSDK);
const secret = "<your_system_generated_unique_user_secret_session>";
const sessionSecret = sha256(serverSecret + secret).toString();
// Setup as usual - the returned bridge public key is used on your client
const bridgePublicKey = await CKUSER.auth.setup(setupParams);
// Check if there is already a session stored for this user
if (simpleSessionDatabase[uid]) {
await CKUSER.auth.self_load(simpleSessionDatabase[uid], setupParams.hostSignPublicKey, sessionSecret);
} else if (sealed) {
// No session - perform a log in
await CKUSER.auth.login({ sealed });
// Store the user session
simpleSessionDatabase[uid] = CKUSER.auth.self_store(sessionSecret);
} else {
throw new Error("Invalid procedure.");
}
// Use the SDK as usual - Call deposit address
let depositAddress = await CKUSER.action.generate_deposit({
chain_id: "bitcoin"
});
console.log("Deposit address", depositAddress);
}
// Fake request, refer below on how to obtain this `sealed` value.
const sealed = "<hex_digest_from_your_bridge_client>";
request("<UID>", sealed).catch(console.log);
Here's an inline bridge public key generation, only use this to retrieve the hex value:
const setupParams = { // Setup parameters like the above };
CKSDK.auth.setup(setupParams).then(CKSDK.auth.get_bridge_pubkey().then(console.log));
We have the following supported language code example for bridge implementation to obtain sealed
:
- Dart (works with Flutter)